diff --git a/include/gmssl/oid.h b/include/gmssl/oid.h index ae817ef5..f35d9418 100644 --- a/include/gmssl/oid.h +++ b/include/gmssl/oid.h @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -173,6 +173,8 @@ enum { OID_cms_signed_and_enveloped_data, OID_cms_encrypted_data, OID_cms_key_agreement_info, + + OID_hss_lms_hashsig, // LMS/HSS public key }; // {iso(1) org(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7)} diff --git a/include/gmssl/sm3_lms.h b/include/gmssl/sm3_lms.h index f2e40cbb..5a743443 100644 --- a/include/gmssl/sm3_lms.h +++ b/include/gmssl/sm3_lms.h @@ -279,18 +279,13 @@ int sm3_hss_verify_update(SM3_HSS_SIGN_CTX *ctx, const uint8_t *data, size_t dat int sm3_hss_verify_finish(SM3_HSS_SIGN_CTX *ctx); -/* -from RFC 9708 - -id-alg-hss-lms-hashsig OBJECT IDENTIFIER ::= { - iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) - pkcs-9(9) smime(16) alg(3) 17 -} -*/ -#include - -#define oid_hss_lms_hashsig oid_pkcs,9,16,3,17 - +// X.509 related +int sm3_hss_public_key_to_der(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen); +int sm3_hss_public_key_from_der(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen); +int sm3_hss_public_key_algor_to_der(uint8_t **out, size_t *outlen); +int sm3_hss_public_key_algor_from_der(const uint8_t **in, size_t *inlen); +int sm3_hss_public_key_info_to_der(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen); +int sm3_hss_public_key_info_from_der(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen); #ifdef __cplusplus diff --git a/src/sm3_lms.c b/src/sm3_lms.c index 65743b47..cfe8a2c1 100644 --- a/src/sm3_lms.c +++ b/src/sm3_lms.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * TODO: @@ -1935,3 +1936,120 @@ int sm3_hss_private_key_size(const int *lms_types, size_t levels, size_t *len) return 1; } + +// X.509 related +int sm3_hss_public_key_to_der(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen) +{ + uint8_t octets[SM3_HSS_PUBLIC_KEY_SIZE]; + uint8_t *p = octets; + size_t len = 0; + + if (!key) { + return 0; + } + + if (sm3_hss_public_key_to_bytes(key, &p, &len) != 1) { + error_print(); + return -1; + } + if (len != sizeof(octets)) { + error_print(); + return -1; + } + if (asn1_bit_octets_to_der(octets, sizeof(octets), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm3_hss_public_key_from_der(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + + if ((ret = asn1_bit_octets_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (dlen != SM3_HSS_PUBLIC_KEY_SIZE) { + error_print(); + return -1; + } + + if (sm3_hss_public_key_from_bytes(key, &d, &dlen) != 1) { + error_print(); + return -1; + } + if (dlen) { + error_print(); + return -1; + } + + return 1; +} + +int sm3_hss_public_key_algor_to_der(uint8_t **out, size_t *outlen) +{ + if (x509_public_key_algor_to_der(OID_hss_lms_hashsig, OID_undef, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm3_hss_public_key_algor_from_der(const uint8_t **in, size_t *inlen) +{ + int ret; + int oid; + int param = OID_undef; + + if ((ret = x509_public_key_algor_from_der(&oid, ¶m, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (oid != OID_hss_lms_hashsig) { + error_print(); + return -1; + } + // param == 0: parameter is empty + // param == 1: parameter is null object + // param == other values, x509_public_key_algor_from_der fail + return 1; +} + +int sm3_hss_public_key_info_to_der(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (sm3_hss_public_key_algor_to_der(NULL, &len) != 1 + || sm3_hss_public_key_to_der(key, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || sm3_hss_public_key_algor_to_der(out, outlen) != 1 + || sm3_hss_public_key_to_der(key, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm3_hss_public_key_info_from_der(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (sm3_hss_public_key_algor_from_der(&d, &dlen) != 1 + || sm3_hss_public_key_from_der(key, &d, &dlen) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + return 1; +} + + diff --git a/src/x509_alg.c b/src/x509_alg.c index b44bd870..56328480 100644 --- a/src/x509_alg.c +++ b/src/x509_alg.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -16,7 +16,9 @@ #include #include #include - +#ifdef ENABLE_SM3_LMS +#include +#endif static uint32_t oid_sm3[] = { 1,2,156,10197,1,401 }; static uint32_t oid_md5[] = { 1,2,840,113549,2,5 }; @@ -558,10 +560,22 @@ err: static uint32_t oid_ec_public_key[] = { oid_x9_62,2,1 }; +/* +from RFC 9708 + +id-alg-hss-lms-hashsig OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) + pkcs-9(9) smime(16) alg(3) 17 +} +*/ +static uint32_t oid_hss_lms_hashsig[] = { oid_pkcs,9,16,3,17 }; static const ASN1_OID_INFO x509_public_key_algors[] = { { OID_ec_public_key, "ecPublicKey", oid_ec_public_key, sizeof(oid_ec_public_key)/sizeof(int), 0, "X9.62 ecPublicKey" }, { OID_rsa_encryption, "rsaEncryption", oid_rsa_encryption, sizeof(oid_rsa_encryption)/sizeof(int), 0, "RSAEncryption" }, +#ifdef ENABLE_SM3_LMS + { OID_hss_lms_hashsig, "hsslmsHashSig", oid_hss_lms_hashsig, sizeof(oid_hss_lms_hashsig)/sizeof(int), 0, "HSS/LMS HashSig" }, +#endif }; static const int x509_public_key_algors_count = @@ -612,6 +626,18 @@ int x509_public_key_algor_to_der(int oid, int curve_or_null, uint8_t **out, size return -1; } break; +#ifdef ENABLE_SM3_LMS + case OID_hss_lms_hashsig: + if (asn1_object_identifier_to_der(oid_hss_lms_hashsig, sizeof(oid_hss_lms_hashsig)/sizeof(int), NULL, &len) != 1 + || asn1_null_to_der(NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(oid_hss_lms_hashsig, sizeof(oid_hss_lms_hashsig)/sizeof(int), out, outlen) != 1 + || asn1_null_to_der(out, outlen) != 1) { + error_print(); + return -1; + } + break; +#endif default: error_print(); return -1; @@ -646,6 +672,9 @@ int x509_public_key_algor_from_der(int *oid , int *curve_or_null, const uint8_t } break; case OID_rsa_encryption: +#ifdef ENABLE_SM3_LMS + case OID_hss_lms_hashsig: +#endif if ((*curve_or_null = asn1_null_from_der(&d, &dlen)) < 0 || asn1_length_is_zero(dlen) != 1) { error_print(); @@ -676,6 +705,9 @@ int x509_public_key_algor_print(FILE *fp, int fmt, int ind, const char *label, c format_print(fp, fmt, ind, "namedCurve: %s\n", ec_named_curve_name(val)); break; case OID_rsa_encryption: +#ifdef ENABLE_SM3_LMS + case OID_hss_lms_hashsig: +#endif if ((val = asn1_null_from_der(&d, &dlen)) < 0) goto err; else if (val) format_print(fp, fmt, ind, "parameters: %s\n", asn1_null_name()); break; diff --git a/tests/sm3_lmstest.c b/tests/sm3_lmstest.c index 3352db77..2847711f 100644 --- a/tests/sm3_lmstest.c +++ b/tests/sm3_lmstest.c @@ -875,6 +875,79 @@ static int test_sm3_hss_sign(void) return 1; } +static int test_sm3_hss_public_key_algor(void) +{ + int lms_types[] = { + LMS_HASH256_M32_H5 + }; + SM3_HSS_KEY key; + uint8_t buf[512]; + const uint8_t *cp; + uint8_t *p; + size_t len; + + + if (sm3_hss_key_generate(&key, lms_types, sizeof(lms_types)/sizeof(lms_types[0])) != 1) { + error_print(); + return -1; + } + + cp = p = buf; + len = 0; + if (sm3_hss_public_key_to_der(&key, &p, &len) != 1) { + error_print(); + return -1; + } + memset(&key, 0, sizeof(SM3_HSS_KEY)); + if (sm3_hss_public_key_from_der(&key, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + + + cp = p = buf; + len = 0; + if (sm3_hss_public_key_algor_to_der(&p, &len) != 1) { + error_print(); + return -1; + } + if (sm3_hss_public_key_algor_from_der(&cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + + + cp = p = buf; + len = 0; + if (sm3_hss_public_key_info_to_der(&key, &p, &len) != 1) { + error_print(); + return -1; + } + memset(&key, 0, sizeof(SM3_HSS_KEY)); + if (sm3_hss_public_key_info_from_der(&key, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + + + printf("%s() ok\n", __FUNCTION__); + return 1; + +} + + int main(void) { #if defined(ENABLE_SM3_LMS_CROSSCHECK) && defined(ENABLE_SHA2) @@ -894,6 +967,7 @@ int main(void) if (test_sm3_hss_sign_level1() != 1) goto err; if (test_sm3_hss_sign_level2() != 1) goto err; if (test_sm3_hss_sign() != 1) goto err; + if (test_sm3_hss_public_key_algor() != 1) goto err; printf("%s all tests passed\n", __FILE__); return 0;