diff --git a/CMakeLists.txt b/CMakeLists.txt index 1605b0ec..f7d1bad4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,11 @@ set(demos demo_zuc ) +option(ENABLE_PRIVATE_KEY_EXPORT "Enable export un-encrypted private key" OFF) +if (ENABLE_PRIVATE_KEY_EXPORT) + add_definitions(-DENABLE_PRIVATE_KEY_EXPORT) + list(APPEND demos demo_sm2_key_export) +endif() option(ENABLE_TLS_DEBUG "Enable TLS and TLCP print debug message" OFF) if (ENABLE_TLS_DEBUG) diff --git a/demos/scripts/certverify.sh b/demos/scripts/certverify.sh index 56895c9b..89e73de4 100755 --- a/demos/scripts/certverify.sh +++ b/demos/scripts/certverify.sh @@ -93,6 +93,11 @@ cat $signcert > $chain cat $cacert >> $chain gmssl certverify -in $chain -cacert $rootcacert +chain_with_root=chain_with_root.pem +cp $chain $chain_with_root +cat $rootcacert >> $chain_with_root +gmssl certverify -in $chain_with_root -cacert $rootcacert + double_certs=double_certs.pem cat $signcert > $double_certs cat $enccert >> $double_certs @@ -104,9 +109,9 @@ cat $cacert >> $double_chain gmssl certverify -in $double_chain -cacert $rootcacert -double_certs gmssl certparse -in $double_chain -#gmssl certverify -in $double_chain -cacert $rootcacert -double_certs -check_crl -#gmssl crlget -cert $signcert -out $crl -#gmssl crlparse -in $crl +gmssl certverify -in $double_chain -cacert $rootcacert -double_certs -check_crl +gmssl crlget -cert $signcert -out $crl +gmssl crlparse -in $crl rm -fr $signcert @@ -115,7 +120,7 @@ rm -fr $crl rm -fr $cacert rm -fr $rootcacert rm -fr $chain +rm -fr $chain_with_root rm -fr $double_certs rm -fr $double_chain - diff --git a/demos/scripts/tlcp_server.sh b/demos/scripts/tlcp_server.sh index 42623698..6b636b21 100755 --- a/demos/scripts/tlcp_server.sh +++ b/demos/scripts/tlcp_server.sh @@ -2,21 +2,21 @@ gmssl sm2keygen -pass 1234 -out rootcakey.pem -gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 -key rootcakey.pem -pass 1234 -out rootcacert.pem -key_usage keyCertSign -key_usage cRLSign +gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 -key rootcakey.pem -pass 1234 -out rootcacert.pem -key_usage keyCertSign -key_usage cRLSign -ca gmssl certparse -in rootcacert.pem gmssl sm2keygen -pass 1234 -out cakey.pem -gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN "Sub CA" -days 3650 -key cakey.pem -pass 1234 -out careq.pem -gmssl reqsign -in careq.pem -days 365 -key_usage keyCertSign -path_len_constraint 0 -cacert rootcacert.pem -key rootcakey.pem -pass 1234 -out cacert.pem +gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN "Sub CA" -key cakey.pem -pass 1234 -out careq.pem +gmssl reqsign -in careq.pem -days 365 -key_usage keyCertSign -path_len_constraint 0 -cacert rootcacert.pem -key rootcakey.pem -pass 1234 -out cacert.pem -ca gmssl certparse -in cacert.pem gmssl sm2keygen -pass 1234 -out signkey.pem -gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -days 365 -key signkey.pem -pass 1234 -out signreq.pem +gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key signkey.pem -pass 1234 -out signreq.pem gmssl reqsign -in signreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out signcert.pem gmssl certparse -in signcert.pem gmssl sm2keygen -pass 1234 -out enckey.pem -gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -days 365 -key enckey.pem -pass 1234 -out encreq.pem +gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN localhost -key enckey.pem -pass 1234 -out encreq.pem gmssl reqsign -in encreq.pem -days 365 -key_usage keyEncipherment -cacert cacert.pem -key cakey.pem -pass 1234 -out enccert.pem gmssl certparse -in enccert.pem @@ -25,15 +25,25 @@ cat enccert.pem >> double_certs.pem cat cacert.pem >> double_certs.pem sudo gmssl tlcp_server -port 443 -cert double_certs.pem -key signkey.pem -pass 1234 -ex_key enckey.pem -ex_pass 1234 -cacert cacert.pem 1>/dev/null 2>/dev/null & +#sudo gmssl tlcp_server -port 443 -cert double_certs.pem -key signkey.pem -pass 1234 -ex_key enckey.pem -ex_pass 1234 1>/dev/null 2>/dev/null & sleep 3 gmssl sm2keygen -pass 1234 -out clientkey.pem -gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN Client -days 365 -key clientkey.pem -pass 1234 -out clientreq.pem +gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN Client -key clientkey.pem -pass 1234 -out clientreq.pem gmssl reqsign -in clientreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out clientcert.pem gmssl certparse -in clientcert.pem -# build and install BabaSSL 8.3.1 +# build and install BabaSSL 8.3.2 +# Download +# ./config enable-ntls; make; sudo make install + +# current /demos/scripts +# /build/bin + openssl version -openssl s_client -enable_ntls -ntls -connect localhost:443 -no_ticket -CAfile rootcacert.pem + +../../build/bin/demo_sm2_key_export clientkey.pem 1234 > clientpkey.pem + +#openssl s_client -enable_ntls -ntls -connect localhost:443 -no_ticket -CAfile rootcacert.pem -sign_cert clientcert.pem -sign_key clientpkey.pem -pass pass:1234 diff --git a/demos/scripts/tlcpdemo.sh b/demos/scripts/tlcpdemo.sh index ec8e1fa1..d3642b40 100755 --- a/demos/scripts/tlcpdemo.sh +++ b/demos/scripts/tlcpdemo.sh @@ -34,5 +34,5 @@ gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN Client -key clientke gmssl reqsign -in clientreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out clientcert.pem gmssl certparse -in clientcert.pem -gmssl tlcp_client -host 127.0.0.1 -cacert rootcacert.pem -cert clientcert.pem -key clientkey.pem -pass 1234 +#gmssl tlcp_client -host 127.0.0.1 -cacert rootcacert.pem -cert clientcert.pem -key clientkey.pem -pass 1234 diff --git a/demos/src/demo_sm2_key_export.c b/demos/src/demo_sm2_key_export.c new file mode 100644 index 00000000..8f96c51d --- /dev/null +++ b/demos/src/demo_sm2_key_export.c @@ -0,0 +1,64 @@ +/* + * Copyright 2014-2022 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = argv[0]; + char *keyfile; + char *pass; + FILE *keyfp = NULL; + SM2_KEY sm2_key; + + if (argc < 3) { + fprintf(stderr, "usage: %s \n", prog); + return -1; + } + keyfile = argv[1]; + pass = argv[2]; + + if (!(keyfp = fopen(keyfile, "rb"))) { + fprintf(stderr, "%s: open file '%s' failure\n", prog, keyfile); + return -1; + } + if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) { + fprintf(stderr, "%s: load key failure\n", prog); + goto end; + } + if (sm2_private_key_info_to_pem(&sm2_key, stdout) != 1) { + fprintf(stderr, "%s: export failure\n", prog); + goto end; + } + ret = 0; + +end: + gmssl_secure_clear(&sm2_key, sizeof(sm2_key)); + if (keyfp) fclose(keyfp); + return ret; +} + + + + + + + + + + + + diff --git a/demos/src/demo_sm2_keyparse.c b/demos/src/demo_sm2_keyparse.c index c9f79055..681fcabc 100644 --- a/demos/src/demo_sm2_keyparse.c +++ b/demos/src/demo_sm2_keyparse.c @@ -11,20 +11,39 @@ #include #include #include +#include #include int main(int argc, char **argv) { - uint8_t buf[4096]; - uint8_t dgst[32]; - int i; + char *prog = argv[0]; + char *keyfile; + char *pass; + FILE *keyfp = NULL; + SM2_KEY sm2_key; - - for (i = 0; i < sizeof(dgst); i++) { - printf("%02x", dgst[i]); + if (argc < 3) { + fprintf(stderr, "usage: %s \n", prog); + return -1; } - printf("\n"); + keyfile = argv[1]; + pass = argv[2]; + + if (!(keyfp = fopen(keyfile, "rb"))) { + fprintf(stderr, "%s: open file '%s' failure\n", prog, keyfile); + return -1; + } + if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) { + fprintf(stderr, "%s: load key failure\n", prog); + fclose(keyfp); + return -1; + } + + sm2_key_print(stdout, 0, 0, "SM2_KEY", &sm2_key); + + gmssl_secure_clear(&sm2_key, sizeof(sm2_key)); + fclose(keyfp); return 0; } diff --git a/include/gmssl/sm2.h b/include/gmssl/sm2.h index 32a56a75..7dd75e69 100644 --- a/include/gmssl/sm2.h +++ b/include/gmssl/sm2.h @@ -225,8 +225,8 @@ ECParameters ::= CHOICE { namedCurve OBJECT IDENTIFIER } int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen); int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen); int sm2_private_key_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); -//int sm2_private_key_to_pem(const SM2_KEY *key, FILE *fp); -//int sm2_private_key_from_pem(SM2_KEY *key, FILE *fp); +int sm2_private_key_to_pem(const SM2_KEY *key, FILE *fp); +int sm2_private_key_from_pem(SM2_KEY *key, FILE *fp); /* AlgorithmIdentifier ::= { @@ -264,8 +264,8 @@ enum { int sm2_private_key_info_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen); int sm2_private_key_info_from_der(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, const uint8_t **in, size_t *inlen); int sm2_private_key_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); -//int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp); -//int sm2_private_key_info_from_pem(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, FILE *fp); +int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp); +int sm2_private_key_info_from_pem(SM2_KEY *key, FILE *fp); /* EncryptedPrivateKeyInfo ::= SEQUENCE { diff --git a/src/sm2_key.c b/src/sm2_key.c index 958cb4b5..5917fc76 100644 --- a/src/sm2_key.c +++ b/src/sm2_key.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -38,7 +39,10 @@ int sm2_key_generate(SM2_KEY *key) memset(key, 0, sizeof(SM2_KEY)); do { - sm2_bn_rand_range(x, SM2_N); + if (sm2_bn_rand_range(x, SM2_N) != 1) { + error_print(); + return -1; + } } while (sm2_bn_is_zero(x)); sm2_bn_to_bytes(x, key->private_key); @@ -46,20 +50,33 @@ int sm2_key_generate(SM2_KEY *key) sm2_jacobian_point_get_xy(P, x, y); sm2_bn_to_bytes(x, key->public_key.x); sm2_bn_to_bytes(y, key->public_key.y); + return 1; } int sm2_key_set_private_key(SM2_KEY *key, const uint8_t private_key[32]) { - memcpy(&key->private_key, private_key, 32); - // FIXEM:检查私钥是否在有效的范围内 + SM2_BN bn; - if (sm2_point_mul_generator(&key->public_key, private_key) != 1) { + sm2_bn_from_bytes(bn, private_key); + + if (sm2_bn_is_zero(bn) + || sm2_bn_cmp(bn, SM2_N) >= 0) { + gmssl_secure_clear(bn, sizeof(bn)); error_print(); return -1; } + memcpy(&key->private_key, private_key, 32); + if (sm2_point_mul_generator(&key->public_key, private_key) != 1) { + gmssl_secure_clear(bn, sizeof(bn)); + gmssl_secure_clear(key, sizeof(SM2_KEY)); + error_print(); + return -1; + } + + gmssl_secure_clear(bn, sizeof(bn)); return 1; } @@ -69,7 +86,11 @@ int sm2_key_set_public_key(SM2_KEY *key, const SM2_POINT *public_key) error_print(); return -1; } - memset(key, 0, sizeof(SM2_KEY)); + if (!sm2_point_is_on_curve(public_key)) { + error_print(); + return -1; + } + gmssl_secure_clear(key, sizeof(SM2_KEY)); key->public_key = *public_key; return 1; } @@ -147,7 +168,6 @@ int sm2_public_key_algor_from_der(const uint8_t **in, size_t *inlen) return ret; } if (oid != OID_ec_public_key) { - printf("%s %d: oid = %d\n", __FILE__, __LINE__, oid); error_print(); return -1; } @@ -158,6 +178,7 @@ int sm2_public_key_algor_from_der(const uint8_t **in, size_t *inlen) return 1; } +#define SM2_PRIVATE_KEY_DER_SIZE 121 int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen) { size_t len = 0; @@ -168,6 +189,10 @@ int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen) size_t params_len = 0; size_t pubkey_len = 0; + if (!key) { + error_print(); + return -1; + } if (ec_named_curve_to_der(OID_sm2, ¶ms_ptr, ¶ms_len) != 1 || sm2_public_key_to_der(key, &pubkey_ptr, &pubkey_len) != 1) { error_print(); @@ -226,7 +251,8 @@ int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen) error_print(); return -1; } - // 这里的逻辑上应该是用一个新的公钥来接收公钥,并且判断这个和私钥是否一致 + + // check if the public key is correct if (pubkey) { SM2_KEY tmp_key; if (sm2_public_key_from_der(&tmp_key, &pubkey, &pubkey_len) != 1 @@ -247,13 +273,12 @@ int sm2_private_key_print(FILE *fp, int fmt, int ind, const char *label, const u return ec_private_key_print(fp, fmt, ind, label, d, dlen); } - -#define SM2_PRIVATE_KEY_MAX_SIZE 512 // 需要测试这个buffer的最大值 +#define SM2_PRIVATE_KEY_INFO_DER_SIZE 150 int sm2_private_key_info_to_der(const SM2_KEY *sm2_key, uint8_t **out, size_t *outlen) { size_t len = 0; - uint8_t prikey[SM2_PRIVATE_KEY_MAX_SIZE]; + uint8_t prikey[SM2_PRIVATE_KEY_DER_SIZE]; uint8_t *p = prikey; size_t prikey_len = 0; @@ -336,37 +361,53 @@ err: return -1; } -#if 0 // 私钥的BASE64编解码可能受到侧信道攻击 -#define SM2_PRIVATE_KEY_INFO_MAX_SIZE 512 // TODO:计算长度 - +#ifdef ENABLE_PRIVATE_KEY_EXPORT int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp) { - uint8_t buf[SM2_PRIVATE_KEY_INFO_MAX_SIZE]; + int ret = -1; + uint8_t buf[SM2_PRIVATE_KEY_INFO_DER_SIZE]; uint8_t *p = buf; size_t len = 0; - if (sm2_private_key_info_to_der(key, &p, &len) != 1 - || pem_write(fp, "PRIVATE KEY", buf, len) != 1) { - memset(buf, 0, sizeof(buf)); + if (!key || !fp) { error_print(); return -1; } - memset(buf, 0, sizeof(buf)); - return 1; + if (sm2_private_key_info_to_der(key, &p, &len) != 1) { + error_print(); + goto end; + } + if (len != sizeof(buf)) { + error_print(); + goto end; + } + if (pem_write(fp, "PRIVATE KEY", buf, len) != 1) { + error_print(); + goto end; + } + ret = 1; +end: + gmssl_secure_clear(buf, sizeof(buf)); + return ret; } -int sm2_private_key_info_from_pem(SM2_KEY *sm2_key, const uint8_t **attrs, size_t *attrslen, FILE *fp) +int sm2_private_key_info_from_pem(SM2_KEY *sm2_key, FILE *fp) { - uint8_t buf[512]; // 这个可能是不够用的,因为attributes可能很长 + uint8_t buf[512]; const uint8_t *cp = buf; size_t len; + const uint8_t *attrs; + size_t attrs_len; if (pem_read(fp, "PRIVATE KEY", buf, &len, sizeof(buf)) != 1 - || sm2_private_key_info_from_der(sm2_key, attrs, attrslen, &cp, &len) != 1 + || sm2_private_key_info_from_der(sm2_key, &attrs, &attrs_len, &cp, &len) != 1 || asn1_length_is_zero(len) != 1) { error_print(); return -1; } + if (attrs_len) { + error_print(); + } return 1; } #endif @@ -404,7 +445,9 @@ int sm2_public_key_info_from_der(SM2_KEY *pub_key, const uint8_t **in, size_t *i return 1; } -#if 0 // 私钥的BASE64编解码可能受到侧信道攻击 +#ifdef ENABLE_PRIVATE_KEY_EXPORT + +// FIXME: side-channel of Base64 int sm2_private_key_to_pem(const SM2_KEY *a, FILE *fp) { uint8_t buf[512]; @@ -469,7 +512,8 @@ int sm2_public_key_info_from_pem(SM2_KEY *a, FILE *fp) return -1; } if (sm2_public_key_info_from_der(a, &cp, &len) != 1 - || len > 0) { + || asn1_length_is_zero(len) != 1) { + error_print(); return -1; } return 1; @@ -500,7 +544,7 @@ int sm2_private_key_info_encrypt_to_der(const SM2_KEY *sm2_key, const char *pass uint8_t **out, size_t *outlen) { int ret = -1; - uint8_t pkey_info[2560]; + uint8_t pkey_info[SM2_PRIVATE_KEY_INFO_DER_SIZE]; uint8_t *p = pkey_info; size_t pkey_info_len = 0; uint8_t salt[16]; @@ -508,9 +552,13 @@ int sm2_private_key_info_encrypt_to_der(const SM2_KEY *sm2_key, const char *pass uint8_t iv[16]; uint8_t key[16]; SM4_KEY sm4_key; - uint8_t enced_pkey_info[5120]; + uint8_t enced_pkey_info[sizeof(pkey_info) + 32]; size_t enced_pkey_info_len; + if (!sm2_key || !pass || !outlen) { + error_print(); + return -1; + } if (sm2_private_key_info_to_der(sm2_key, &p, &pkey_info_len) != 1 || rand_bytes(salt, sizeof(salt)) != 1 || rand_bytes(iv, sizeof(iv)) != 1 @@ -519,6 +567,12 @@ int sm2_private_key_info_encrypt_to_der(const SM2_KEY *sm2_key, const char *pass error_print(); goto end; } + /* + if (pkey_info_len != sizeof(pkey_info)) { + error_print(); + goto end; + } + */ sm4_set_encrypt_key(&sm4_key, key); if (sm4_cbc_padding_encrypt( &sm4_key, iv, pkey_info, pkey_info_len, @@ -530,11 +584,12 @@ int sm2_private_key_info_encrypt_to_der(const SM2_KEY *sm2_key, const char *pass error_print(); goto end; } + ret = 1; end: - memset(pkey_info, 0, sizeof(pkey_info)); - memset(key, 0, sizeof(key)); - memset(&sm4_key, 0, sizeof(sm4_key)); + gmssl_secure_clear(pkey_info, sizeof(pkey_info)); + gmssl_secure_clear(key, sizeof(key)); + gmssl_secure_clear(&sm4_key, sizeof(sm4_key)); return ret; } @@ -559,6 +614,10 @@ int sm2_private_key_info_decrypt_from_der(SM2_KEY *sm2, const uint8_t *cp = pkey_info; size_t pkey_info_len; + if (!sm2 || !attrs || !attrs_len || !pass || !in || !(*in) || !inlen) { + error_print(); + return -1; + } if (pkcs8_enced_private_key_info_from_der(&salt, &saltlen, &iter, &keylen, &prf, &cipher, &iv, &ivlen, &enced_pkey_info, &enced_pkey_info_len, in, inlen) != 1 || asn1_check(keylen == -1 || keylen == 16) != 1 @@ -579,19 +638,13 @@ int sm2_private_key_info_decrypt_from_der(SM2_KEY *sm2, || sm2_private_key_info_from_der(sm2, attrs, attrs_len, &cp, &pkey_info_len) != 1 || asn1_length_is_zero(pkey_info_len) != 1) { error_print(); - - if (pkey_info_len) { - format_bytes(stderr, 0, 0, "700", cp, pkey_info_len); - } - - goto end; } ret = 1; end: - memset(&sm4_key, 0, sizeof(sm4_key)); - memset(key, 0, sizeof(key)); - memset(pkey_info, 0, sizeof(pkey_info)); + gmssl_secure_clear(&sm4_key, sizeof(sm4_key)); + gmssl_secure_clear(key, sizeof(key)); + gmssl_secure_clear(pkey_info, sizeof(pkey_info)); return ret; } @@ -601,6 +654,10 @@ int sm2_private_key_info_encrypt_to_pem(const SM2_KEY *sm2_key, const char *pass uint8_t *p = buf; size_t len = 0; + if (!fp) { + error_print(); + return -1; + } if (sm2_private_key_info_encrypt_to_der(sm2_key, pass, &p, &len) != 1) { error_print(); return -1; @@ -620,13 +677,13 @@ int sm2_private_key_info_decrypt_from_pem(SM2_KEY *key, const char *pass, FILE * const uint8_t *attrs; size_t attrs_len; - if (pem_read(fp, "ENCRYPTED PRIVATE KEY", buf, &len, sizeof(buf)) != 1 - || sm2_private_key_info_decrypt_from_der(key, &attrs, &attrs_len, pass, &cp, &len) != 1) { + if (!key || !pass || !fp) { error_print(); return -1; } - if (asn1_length_is_zero(len) != 1) { - format_bytes(stderr, 0, 0, "", cp, len); + if (pem_read(fp, "ENCRYPTED PRIVATE KEY", buf, &len, sizeof(buf)) != 1 + || sm2_private_key_info_decrypt_from_der(key, &attrs, &attrs_len, pass, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { error_print(); return -1; }