Support HSS/XMSS/XMSSMT certificate, CSR, and CRL

LMS and SPHINCS+ do not have official OID, so officially supported by X.509
This commit is contained in:
Zhi Guan
2026-01-18 21:13:58 +08:00
parent e8eb873c47
commit 05ba2f8e54
8 changed files with 263 additions and 129 deletions

View File

@@ -19,13 +19,14 @@
#include <gmssl/hex.h>
#include <gmssl/x509.h>
#include <gmssl/x509_ext.h>
#include <gmssl/x509_alg.h>
static const char *options =
"[-C str] [-ST str] [-L str] [-O str] [-OU str] -CN str"
" -serial_len num"
" -days num"
" -key pem -pass pass"
" -key pem [-algor str] [-pass pass]"
" [-sm2_id str | -sm2_id_hex hex]"
" [-gen_authority_key_id]"
" [-gen_subject_key_id]"
@@ -45,6 +46,7 @@ static char *usage =
" -serial_len num Serial number length in bytes\n"
" -days num Validity peroid in days\n"
" -key file Private key file in PEM format\n"
" -algor str Public key algorithm\n"
" -pass pass Password for decrypting private key file\n"
" -sm2_id str Signer's ID in SM2 signature algorithm\n"
" -sm2_id_hex hex Signer's ID in hex format\n"
@@ -154,8 +156,9 @@ int certgen_main(int argc, char **argv)
// Private Key
FILE *keyfp = NULL;
char *pass = NULL;
SM2_KEY sm2_key;
X509_KEY x509_key;
int algor = OID_ec_public_key;
int sign_algor = OID_sm2sign_with_sm3;
char signer_id[SM2_MAX_ID_LENGTH + 1] = {0};
size_t signer_id_len = 0;
@@ -264,6 +267,13 @@ int certgen_main(int argc, char **argv)
fprintf(stderr, "%s: open '%s' failure : %s\n", prog, str, strerror(errno));
goto end;
}
} else if (!strcmp(*argv, "-algor")) {
if (--argc < 1) goto bad;
str = *(++argv);
if ((algor = x509_public_key_algor_from_name(str)) == OID_undef) {
fprintf(stderr, "%s: invalid algor '%s'\n", prog, str);
goto end;
}
} else if (!strcmp(*argv, "-pass")) {
if (--argc < 1) goto bad;
pass = *(++argv);
@@ -390,24 +400,25 @@ bad:
printf("usage: gmssl %s %s\n\n", prog, options);
goto end;
}
if (!pass) {
if (!pass && algor != OID_ec_public_key) {
fprintf(stderr, "%s: option `-pass` required\n", prog);
printf("usage: gmssl %s %s\n\n", prog, options);
goto end;
}
if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) {
if (x509_private_key_from_file(&x509_key, algor, pass, keyfp) != 1) {
fprintf(stderr, "%s: load private key failed\n", prog);
goto end;
}
if (x509_key_get_sign_algor(&x509_key, &sign_algor) != 1) {
fprintf(stderr, "%s: inner error\n", prog);
goto end;
}
if (!signer_id_len) {
strcpy(signer_id, SM2_DEFAULT_ID);
signer_id_len = strlen(SM2_DEFAULT_ID);
}
if (x509_key_set_sm2_key(&x509_key, &sm2_key) != 1) {
//
goto end;
}
// Serial
if (rand_bytes(serial, sizeof(serial)) != 1) {
@@ -508,7 +519,7 @@ bad:
if (x509_cert_sign_to_der(
X509_version_v3,
serial, serial_len,
OID_sm2sign_with_sm3,
sign_algor,
name, namelen,
not_before, not_after,
name, namelen,
@@ -530,7 +541,7 @@ bad:
if (x509_cert_sign_to_der(
X509_version_v3,
serial, serial_len,
OID_sm2sign_with_sm3,
sign_algor,
name, namelen,
not_before, not_after,
name, namelen,
@@ -550,7 +561,7 @@ bad:
ret = 0;
end:
gmssl_secure_clear(&sm2_key, sizeof(SM2_KEY));
x509_key_cleanup(&x509_key);
if (cert) free(cert);
if (keyfp) fclose(keyfp);
if (outfile && outfp) fclose(outfp);

View File

@@ -24,7 +24,7 @@
static const char *usage =
" -in revoked_certs"
" -cacert pem -key pem -pass pass [-sm2_id str | -sm2_id_hex hex]"
" -cacert pem -key pem [-pass pass] [-sm2_id str | -sm2_id_hex hex]"
" [-next_update time] "
" [-gen_authority_key_id]"
" [-crl_num num]"
@@ -76,11 +76,13 @@ int crlgen_main(int argc, char **argv)
size_t cacert_len = 0;
FILE *keyfp = NULL;
char *pass = NULL;
SM2_KEY sm2_key;
X509_KEY sign_key;
X509_KEY x509_key;
X509_KEY x509_pub;
char signer_id[SM2_MAX_ID_LENGTH + 1] = {0};
size_t signer_id_len = 0;
int sign_algor = OID_undef;
const uint8_t *issuer;
size_t issuer_len;
time_t this_update = time(NULL);
@@ -231,32 +233,44 @@ bad:
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
goto end;
}
if (!pass) {
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
fprintf(stderr, "%s: `-pass` option required\n", prog);
goto end;
}
if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) {
fprintf(stderr, "%s: load private key failure\n", prog);
goto end;
}
if (!signer_id_len) {
strcpy(signer_id, SM2_DEFAULT_ID);
signer_id_len = strlen(SM2_DEFAULT_ID);
}
if (x509_key_set_sm2_key(&sign_key, &sm2_key) != 1) {
error_print();
goto end;
}
if (x509_cert_get_subject(cacert, cacert_len, &issuer, &issuer_len) != 1) {
fprintf(stderr, "%s: parse CA certificate failure\n", prog);
goto end;
}
if (x509_cert_get_subject_public_key(cacert, cacert_len, &x509_pub) != 1) {
fprintf(stderr, "%s: parse CA certificate failure\n", prog);
goto end;
}
if (!pass && x509_pub.algor == OID_ec_public_key) {
fprintf(stderr, "usage: gmssl %s %s\n", prog, usage);
fprintf(stderr, "%s: `-pass` option required\n", prog);
goto end;
}
if (x509_private_key_from_file(&x509_key, x509_pub.algor, pass, keyfp) != 1) {
fprintf(stderr, "%s: load private key failure\n", prog);
goto end;
}
if (x509_public_key_equ(&x509_key, &x509_pub) != 1) {
fprintf(stderr, "%s: certificate and private key not match\n", prog);
goto end;
}
if (x509_key_get_sign_algor(&x509_key, &sign_algor) != 1) {
fprintf(stderr, "%s: inner error\n", prog);
goto end;
}
if (!signer_id_len) {
strcpy(signer_id, SM2_DEFAULT_ID);
signer_id_len = strlen(SM2_DEFAULT_ID);
}
// Extensions
if (gen_authority_key_id) {
if (x509_crl_exts_add_default_authority_key_identifier(exts, &extslen, sizeof(exts), &sign_key) != 1) {
if (x509_crl_exts_add_default_authority_key_identifier(exts, &extslen, sizeof(exts), &x509_key) != 1) {
fprintf(stderr, "%s: inner error\n", prog);
goto end;
}
@@ -288,12 +302,12 @@ bad:
if (x509_crl_sign_to_der(
X509_version_v2,
OID_sm2sign_with_sm3,
sign_algor,
issuer, issuer_len,
this_update, next_update,
revoked_certs, revoked_certs_len,
extslen ? exts : NULL, extslen,
&sign_key, signer_id, signer_id_len,
&x509_key, signer_id, signer_id_len,
NULL, &outlen) != 1) {
fprintf(stderr, "%s: inner error\n", prog);
goto end;
@@ -306,12 +320,12 @@ bad:
outlen = 0;
if (x509_crl_sign_to_der(
X509_version_v2,
OID_sm2sign_with_sm3,
sign_algor,
issuer, issuer_len,
this_update, next_update,
revoked_certs, revoked_certs_len,
extslen ? exts : NULL, extslen,
&sign_key, signer_id, signer_id_len,
&x509_key, signer_id, signer_id_len,
&out, &outlen) != 1) {
fprintf(stderr, "%s: inner error\n", prog);
goto end;
@@ -323,8 +337,7 @@ bad:
ret = 0;
end:
gmssl_secure_clear(&sm2_key, sizeof(SM2_KEY)); // FIXME: sm2_clean?
gmssl_secure_clear(&sign_key, sizeof(X509_KEY)); // x509_key_clean?
x509_key_cleanup(&x509_key);
if (revoked_certs) free(revoked_certs);
if (keyfp) fclose(keyfp);
if (cacert) free(cacert);

View File

@@ -18,19 +18,26 @@
#include <gmssl/pkcs8.h>
#include <gmssl/x509.h>
#include <gmssl/x509_req.h>
#include <gmssl/x509_alg.h>
static const char *options =
"[-C str] [-ST str] [-L str] [-O str] [-OU str] -CN str"
" -key pem -pass pass"
" -key file [-algor str] [-pass pass]"
" [-sm2_id str | -sm2_id_hex hex]"
" [-out pem]";
static char *usage =
"Options\n"
"\n"
" -key file Private key file in PEM format\n"
" -key file Private key file in PKCS#8 PEM format or raw binary\n"
" -algor str Public key algorithm, supported algorithms:\n"
" * ecPublicKey\n"
" * lms-hashsig\n"
" * hss-lms-hashsig\n"
" * xmss-hashsig\n"
" * xmssmt-hashsig\n"
" * shpincs-hashsig\n"
" -pass pass Password for decrypting private key file\n"
" -sm2_id str Signer's ID in SM2 signature algorithm\n"
" -sm2_id_hex hex Signer's ID in hex format\n"
@@ -79,10 +86,10 @@ int reqgen_main(int argc, char **argv)
// Private Key
FILE *keyfp = NULL;
char *pass = NULL;
SM2_KEY sm2_key;
X509_KEY x509_key;
int algor = OID_ec_public_key;
char signer_id[SM2_MAX_ID_LENGTH + 1] = {0};
size_t signer_id_len = 0;
X509_KEY x509_key;
// Output
char *outfile = NULL;
@@ -131,6 +138,13 @@ int reqgen_main(int argc, char **argv)
fprintf(stderr, "%s: open '%s' failure : %s\n", prog, str, strerror(errno));
goto end;
}
} else if (!strcmp(*argv, "-algor")) {
if (--argc < 1) goto bad;
str = *(++argv);
if ((algor = x509_public_key_algor_from_name(str)) == OID_undef) {
fprintf(stderr, "%s: invalid algor '%s'\n", prog, str);
goto end;
}
} else if (!strcmp(*argv, "-pass")) {
if (--argc < 1) goto bad;
pass = *(++argv);
@@ -184,25 +198,22 @@ bad:
printf("usage: gmssl %s %s\n\n", prog, options);
goto end;
}
if (!pass) {
if (!pass && algor == OID_ec_public_key) {
fprintf(stderr, "%s: `-pass` option required\n", prog);
printf("usage: gmssl %s %s\n\n", prog, options);
goto end;
}
if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) {
if (x509_private_key_from_file(&x509_key, algor, pass, keyfp) != 1) {
fprintf(stderr, "%s: load private key failed\n", prog);
goto end;
}
if (!signer_id_len) {
strcpy(signer_id, SM2_DEFAULT_ID);
signer_id_len = strlen(SM2_DEFAULT_ID);
}
if (x509_key_set_sm2_key(&x509_key, &sm2_key) != 1) {
// output error message
//error_print();
goto end;
}
if (x509_name_set(name, &namelen, sizeof(name), country, state, locality, org, org_unit, common_name) != 1) {
fprintf(stderr, "%s: set Subject Name error\n", prog);
@@ -226,7 +237,7 @@ bad:
}
ret = 0;
end:
gmssl_secure_clear(&sm2_key, sizeof(SM2_KEY));
x509_key_cleanup(&x509_key);
if (keyfp) fclose(keyfp);
if (outfile && outfp) fclose(outfp);
return ret;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
* Copyright 2014-2026 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.
@@ -18,6 +18,9 @@
#include <gmssl/x509.h>
#include <gmssl/x509_ext.h>
#include <gmssl/x509_req.h>
#include <gmssl/x509_alg.h>
#include <gmssl/x509_key.h>
#include <gmssl/error.h>
static const char *options =
@@ -25,7 +28,7 @@ static const char *options =
" [-req_sm2_id str | -req_sm2_id_hex hex]"
" [-serial_len num]"
" -days num"
" -cacert pem -key file -pass pass"
" -cacert pem -key file [-pass pass]"
" [-sm2_id str | -sm2_id_hex hex]"
" [-gen_authority_key_id]"
" [-gen_subject_key_id]"
@@ -172,15 +175,17 @@ int reqsign_main(int argc, char **argv)
size_t cacertlen;
FILE *keyfp = NULL;
char *pass = NULL;
SM2_KEY sm2_key;
X509_KEY x509_key;
char signer_id[SM2_MAX_ID_LENGTH + 1] = {0};
size_t signer_id_len = 0;
// Algor
int sign_algor = OID_undef;
// Issuer from CA certificate
const uint8_t *issuer;
size_t issuer_len;
SM2_KEY sm2_issuer_public_key;
//SM2_KEY sm2_issuer_public_key;
X509_KEY issuer_public_key;
// Output
@@ -429,11 +434,6 @@ bad:
printf("usage: gmssl %s %s\n\n", prog, options);
goto end;
}
if (!pass) {
fprintf(stderr, "%s: '-pass' option required\n", prog);
printf("usage: gmssl %s %s\n\n", prog, options);
goto end;
}
if (x509_req_from_pem(req, &reqlen, sizeof(req), infp) != 1) {
fprintf(stderr, "%s: parse CSR failure\n", prog);
@@ -459,23 +459,28 @@ bad:
fprintf(stderr, "%s: parse CA certificate failure\n", prog);
goto end;
}
if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) {
if (!pass && issuer_public_key.algor == OID_ec_public_key) {
fprintf(stderr, "%s: '-pass' option required\n", prog);
printf("usage: gmssl %s %s\n\n", prog, options);
goto end;
}
if (x509_private_key_from_file(&x509_key, issuer_public_key.algor, pass, keyfp) != 1) {
fprintf(stderr, "%s: load private key failure\n", prog);
goto end;
}
// 这里可能需要修改一下x509_key和sm2_key对比
if (sm2_public_key_equ(&sm2_key, &issuer_public_key.u.sm2_key) != 1) {
if (x509_public_key_equ(&x509_key, &issuer_public_key) != 1) {
fprintf(stderr, "%s: private key and CA certificate not match\n", prog);
goto end;
}
if (x509_key_get_sign_algor(&x509_key, &sign_algor) != 1) {
error_print();
goto end;
}
if (!signer_id_len) {
strcpy(signer_id, SM2_DEFAULT_ID);
signer_id_len = strlen(SM2_DEFAULT_ID);
}
if (x509_key_set_sm2_key(&x509_key, &sm2_key) != 1) {
//fprint
goto end;
}
if (rand_bytes(serial, serial_len) != 1) {
fprintf(stderr, "%s: random number generator error\n", prog);
@@ -569,7 +574,7 @@ bad:
if (x509_cert_sign_to_der(
X509_version_v3,
serial, serial_len,
OID_sm2sign_with_sm3,
sign_algor,
issuer, issuer_len,
not_before, not_after,
subject, subject_len,
@@ -591,7 +596,7 @@ bad:
if (x509_cert_sign_to_der(
X509_version_v3,
serial, serial_len,
OID_sm2sign_with_sm3,
sign_algor,
issuer, issuer_len,
not_before, not_after,
subject, subject_len,
@@ -611,7 +616,7 @@ bad:
}
ret = 0;
end:
gmssl_secure_clear(&x509_key, sizeof(SM2_KEY));
x509_key_cleanup(&x509_key);
if (cert) free(cert);
if (keyfp) fclose(keyfp);
if (infile && infp) fclose(infp);