From 9b215c513850cf753369f9ea00d7a42c20ed8206 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 24 May 2021 13:59:01 -0700 Subject: [PATCH] Fixes for DH Pub key import/export and new test case. Improve `wc_DhParamsToDer`. --- certs/statickeys/dh-ffdhe2048-pub.der | Bin 0 -> 552 bytes certs/statickeys/dh-ffdhe2048-pub.pem | 14 +++ certs/statickeys/gen-static.sh | 4 + certs/statickeys/include.am | 4 +- wolfcrypt/src/asn.c | 128 ++++++++++---------------- wolfcrypt/test/test.c | 59 ++++++++---- 6 files changed, 113 insertions(+), 96 deletions(-) create mode 100644 certs/statickeys/dh-ffdhe2048-pub.der create mode 100644 certs/statickeys/dh-ffdhe2048-pub.pem diff --git a/certs/statickeys/dh-ffdhe2048-pub.der b/certs/statickeys/dh-ffdhe2048-pub.der new file mode 100644 index 0000000000000000000000000000000000000000..e7b3393d1e9a9133310539b3083a8f762569ce93 GIT binary patch literal 552 zcmXqLVp29}ViafN)N1o+`_9YA%xKWW$idXa$jI;?3fBGziCDDTYu5TZVG8QDHXm>7 zJlcFt*KF#_hh~lhgWLt5^S~CaM^J zm5*o3yU?1P8fyDi>hsoc;kf$nlcqELc?upp>n?w^tn=3A_b-ZMKSnGxTl?J9V9hCi z539zjtQc+MaOzONOk!)8c!UzF*dby?vfsv|Ey!eff!Z zT)74FnEpIG`~A_I112nIHB9sqCl>vi^Rl)1f1kgQ(YsHL&4>S4OZ()nEwa)B9f?*-jRT8ZpzM-u}l$jZRf#K_=l@AD+bt?+*$ zQ!#g{zuR*?{&|ipp^kx_E8|-BRB@S_i0<2XSnllcDDfHb|EJkX&;E5rUT(Qk_tbaV zS4tiwKl(domH)n!%x1&52{Em)n`S;>-TG;pg^=wzt&xbH3Y~n1A%_jycOk zr(bZ<)73LlIBI=AAir09N6X@LmAb`mdN?X_R6Ce1FUUA2rRt_P+o$Qv>&+)+#d#)8 z3E|&*-@ee*c)D-9l(z#{;TFk##(U3y7ENX|k6AeP!1LwZmltK*e{?!wmd)kd{qjQ3 zS$@N_O3y7%^uCUr*v*zF&whKgwtwr7-Jy^776ir=r^Q~}_QOTs!6#0cT&CDRRUAzK D)q4*H literal 0 HcmV?d00001 diff --git a/certs/statickeys/dh-ffdhe2048-pub.pem b/certs/statickeys/dh-ffdhe2048-pub.pem new file mode 100644 index 000000000..eea809986 --- /dev/null +++ b/certs/statickeys/dh-ffdhe2048-pub.pem @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICJDCCARcGCSqGSIb3DQEDATCCAQgCggEBAP//////////rfhUWKK7Spqv3FYg +Jz088di5xYPOLTaVqeE2QRRkM/vMk53OJJs++X0v42NjDHXY9oGyAq7EYXrT3x7V +1f1lYSQz9R9fBm7QhWNlVT3tGvO1VxNef1fJNZhPDHDg5ot34qaJ2vPv6HId8Vih +Nq3nNTCsyk9IOnl6vAqxgrMk+2HRCKlLssjj+7lq2rdg1/RoHU9Co945TfSuVu3n +Y3K7GQsHp8juCm1wngL84c334uzANATNKDQvYZFy/pzphYP/jk8SMu7ygYPD/jsb +TG+tczu1/LwuwiAFxY7xg30Wg7LG80omwbLv+ohrQjhhKFyX//////////8CAQID +ggEFAAKCAQBNP0zkbEZx/2ECcwtlT0bnLg+eQQRVQVGJqV6EvHoKNTQVvrHDHs3H +WheYX/+WPRub+swfHqcii5XuK9R04mPi/ZyqT75kaYMxXpBchV2ymeAFtfK2Gc0G +zaizWY2HhH+PCe69YW/FzbicpxWX0EQuLS4yIMU731BvjRe4hKNnJH6j7IwIeGwl +iALToGjOGiVGLptMgvTrs8kdFwySlFQPtd8/cUUzl02HGktACnG0Gb4zvc/zFWMG +N1yhncDnp4vToms/8ULINmsKQ4vp0IzNDzHNIuc5yI3rXZGLBm4fB9urK0+F+LtV +471wUVxzZl3RtvhEEODyCRxtAl38egiC +-----END PUBLIC KEY----- diff --git a/certs/statickeys/gen-static.sh b/certs/statickeys/gen-static.sh index 58289eecb..f81e52709 100644 --- a/certs/statickeys/gen-static.sh +++ b/certs/statickeys/gen-static.sh @@ -10,3 +10,7 @@ openssl ec -inform pem -in certs/statickeys/ecc-secp256r1.pem -outform der -out # Using one generated and capture with wolfSSL using wc_DhGenerateKeyPair (openssl generates DH keys with 2048-bits... based on the DH "p" prime size) #openssl genpkey -paramfile certs/statickeys/dh-ffdhe2048-params.pem -out certs/statickeys/dh-ffdhe2048.der openssl pkey -inform der -in certs/statickeys/dh-ffdhe2048.der -outform pem -out certs/statickeys/dh-ffdhe2048.pem +openssl pkey -inform der -in certs/statickeys/dh-ffdhe2048.der -outform der -out certs/statickeys/dh-ffdhe2048-pub.der -pubout +# Export DH public key as DER and convert to PEM +openssl pkey -inform der -in certs/statickeys/dh-ffdhe2048-pub.der -outform pem -out certs/statickeys/dh-ffdhe2048-pub.pem +openssl pkey -inform der -in certs/statickeys/dh-ffdhe2048-pub.der -outform pem -out certs/statickeys/dh-ffdhe2048-pub.pem -pubin diff --git a/certs/statickeys/include.am b/certs/statickeys/include.am index 988b03dcc..123764dd5 100644 --- a/certs/statickeys/include.am +++ b/certs/statickeys/include.am @@ -14,4 +14,6 @@ EXTRA_DIST += \ EXTRA_DIST += \ certs/statickeys/dh-ffdhe2048-params.pem \ certs/statickeys/dh-ffdhe2048.der \ - certs/statickeys/dh-ffdhe2048.pem + certs/statickeys/dh-ffdhe2048.pem \ + certs/statickeys/dh-ffdhe2048-pub.der \ + certs/statickeys/dh-ffdhe2048-pub.pem diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 880d1fb8a..94ea32a28 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4731,11 +4731,10 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) if (ret == ASN_DH_KEY_E) { *inOutIdx = temp; - /* the version (0) */ - if (GetASNInt(input, inOutIdx, &length, inSz) < 0) { - return ASN_PARSE_E; + /* the version (0) - private only (for public skip) */ + if (GetASNInt(input, inOutIdx, &length, inSz) == 0) { + *inOutIdx += length; } - *inOutIdx += length; /* Size of dhKeyAgreement section */ if (GetSequence(input, inOutIdx, &length, inSz) < 0) @@ -4796,7 +4795,7 @@ int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) /* Export DH Key (private or public) */ int wc_DhKeyToDer(DhKey* key, byte* output, word32* outSz, int exportPriv) { - int privSz = 0, pubSz = 0, keySz; + int ret, privSz = 0, pubSz = 0, keySz; word32 idx, total; if (key == NULL || outSz == NULL) { @@ -4815,19 +4814,23 @@ int wc_DhKeyToDer(DhKey* key, byte* output, word32* outSz, int exportPriv) idx = 1 + SetLength(pubSz, NULL) + pubSz; /* +1 for ASN_BIT_STRING */ } keySz = idx; - /* integer - g */ - idx += SetASNIntMP(&key->g, -1, NULL); - /* integer - p */ - idx += SetASNIntMP(&key->p, -1, NULL); - /* sequence */ - idx += SetSequence(idx, NULL); + + /* DH Parameters sequence with P and G */ + total = 0; + ret = wc_DhParamsToDer(key, NULL, &total); + if (ret != LENGTH_ONLY_E) + return ret; + idx += total; + /* object dhKeyAgreement 1.2.840.113549.1.3.1 */ idx += SetObjectId(sizeof(keyDhOid), NULL); idx += sizeof(keyDhOid); /* sequence */ idx += SetSequence(idx, NULL); - /* version: 0 (ASN_INTEGER, 0x01, 0x00) */ - idx += 3; + if (exportPriv) { + /* version: 0 (ASN_INTEGER, 0x01, 0x00) */ + idx += 3; + } /* sequence */ total = idx + SetSequence(idx, NULL); @@ -4845,20 +4848,24 @@ int wc_DhKeyToDer(DhKey* key, byte* output, word32* outSz, int exportPriv) /* sequence */ idx = SetSequence(total, output); - /* version: 0 */ - idx += SetMyVersion(0, output + idx, 0); + if (exportPriv) { + /* version: 0 */ + idx += SetMyVersion(0, output + idx, 0); + } /* sequence - all but pub/priv */ idx += SetSequence(total - keySz - idx, output + idx); /* object dhKeyAgreement 1.2.840.113549.1.3.1 */ idx += SetObjectId(sizeof(keyDhOid), output + idx); XMEMCPY(output + idx, keyDhOid, sizeof(keyDhOid)); idx += sizeof(keyDhOid); - /* sequence */ - idx += SetSequence(total - keySz - idx, output + idx); - /* integer - p */ - idx += SetASNIntMP(&key->p, -1, output + idx); - /* integer - g */ - idx += SetASNIntMP(&key->g, -1, output + idx); + + /* DH Parameters sequence with P and G */ + total = *outSz - idx; + ret = wc_DhParamsToDer(key, output + idx, &total); + if (ret < 0) + return ret; + idx += total; + /* octect string: priv */ if (exportPriv) { idx += SetOctetString(privSz, output + idx); @@ -4892,77 +4899,42 @@ int wc_DhPrivKeyToDer(DhKey* key, byte* out, word32* outSz) * version 2 build. * * return bytes written on success */ -int wc_DhParamsToDer(DhKey* key, byte* out, word32* outSz) +int wc_DhParamsToDer(DhKey* key, byte* output, word32* outSz) { - word32 sz = 0, idx = 0; - int pSz = 0, gSz = 0, ret; - byte scratch[MAX_LENGTH_SZ]; + word32 idx, total; if (key == NULL || outSz == NULL) { return BAD_FUNC_ARG; } - pSz = mp_unsigned_bin_size(&key->p); - if (pSz < 0) { - return pSz; - } - if (mp_leading_bit(&key->p)) { - pSz++; - } + /* determine size */ + /* integer - g */ + idx = SetASNIntMP(&key->g, -1, NULL); + /* integer - p */ + idx += SetASNIntMP(&key->p, -1, NULL); + total = idx; + /* sequence */ + idx += SetSequence(idx, NULL); - gSz = mp_unsigned_bin_size(&key->g); - if (gSz < 0) { - return gSz; - } - if (mp_leading_bit(&key->g)) { - gSz++; - } - - sz = ASN_TAG_SZ; /* Integer */ - sz += SetLength(pSz, scratch); - sz += ASN_TAG_SZ; /* Integer */ - sz += SetLength(gSz, scratch); - sz += gSz + pSz; - - if (out == NULL) { - byte seqScratch[MAX_SEQ_SZ]; - - *outSz = sz + SetSequence(sz, seqScratch); + if (output == NULL) { + *outSz = idx; return LENGTH_ONLY_E; } - - if (*outSz < MAX_SEQ_SZ || *outSz < sz) { + /* make sure output fits in buffer */ + if (idx > *outSz) { return BUFFER_E; } - idx += SetSequence(sz, out); - if (*outSz < idx + sz) { - return BUFFER_E; - } - out[idx++] = ASN_INTEGER; - idx += SetLength(pSz, out + idx); - if (mp_leading_bit(&key->p)) { - out[idx++] = 0x00; - pSz -= 1; /* subtract 1 from size to account for leading 0 */ - } - ret = mp_to_unsigned_bin(&key->p, out + idx); - if (ret != MP_OKAY) { - return BUFFER_E; - } - idx += pSz; + /* write DH parameters */ + /* sequence - for P and G only */ + idx = SetSequence(total, output); + /* integer - p */ + idx += SetASNIntMP(&key->p, -1, output + idx); + /* integer - g */ + idx += SetASNIntMP(&key->g, -1, output + idx); + *outSz = idx; - out[idx++] = ASN_INTEGER; - idx += SetLength(gSz, out + idx); - if (mp_leading_bit(&key->g)) { - out[idx++] = 0x00; - gSz -= 1; /* subtract 1 from size to account for leading 0 */ - } - ret = mp_to_unsigned_bin(&key->g, out + idx); - if (ret != MP_OKAY) { - return BUFFER_E; - } - idx += gSz; return idx; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 8036ece17..3952e5e24 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -11997,6 +11997,7 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #if defined(WOLFSSL_DH_EXTRA) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) static const char* dhKeyFile = CERT_ROOT "statickeys/dh-ffdhe2048.der"; + static const char* dhKeyPubFile = CERT_ROOT "statickeys/dh-ffdhe2048-pub.der"; #endif #endif #ifndef NO_DSA @@ -16657,8 +16658,9 @@ WOLFSSL_TEST_SUBROUTINE int dh_test(void) ERROR_OUT(-8120, done); } -#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) +#ifndef NO_ASN { + /* DH Private - Key Export / Import */ #ifdef WOLFSSL_SMALL_STACK byte *tmp2; #else @@ -16666,19 +16668,19 @@ WOLFSSL_TEST_SUBROUTINE int dh_test(void) #endif XFILE file = XFOPEN(dhKeyFile, "rb"); if (!file) - ERROR_OUT(-8121, done); + ERROR_OUT(-8130, done); bytes = (word32)XFREAD(tmp, 1, DH_TEST_TMP_SIZE, file); XFCLOSE(file); #ifdef WOLFSSL_SMALL_STACK tmp2 = (byte*)XMALLOC(DH_TEST_TMP_SIZE, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (tmp2 == NULL) - ERROR_OUT(-8122, done); + ERROR_OUT(-8131, done); #endif idx = 0; XMEMSET(tmp2, 0, DH_TEST_TMP_SIZE); - /* Import DH key as DER */ + /* Import DH Private key as DER */ ret = wc_DhKeyDecode(tmp, &idx, key, bytes); if (ret == 0) { /* Export as DER */ @@ -16688,7 +16690,31 @@ WOLFSSL_TEST_SUBROUTINE int dh_test(void) /* Verify export matches original */ if (ret <= 0 || bytes != idx || XMEMCMP(tmp, tmp2, bytes) != 0) { - ERROR_OUT(-8123, done); + ERROR_OUT(-8132, done); + } + + + /* DH Public Key - Export / Import */ + file = XFOPEN(dhKeyPubFile, "rb"); + if (!file) + ERROR_OUT(-8133, done); + bytes = (word32)XFREAD(tmp, 1, DH_TEST_TMP_SIZE, file); + XFCLOSE(file); + + idx = 0; + XMEMSET(tmp2, 0, DH_TEST_TMP_SIZE); + + /* Import DH Public key as DER */ + ret = wc_DhKeyDecode(tmp, &idx, key, bytes); + if (ret == 0) { + /* Export as DER */ + idx = DH_TEST_TMP_SIZE; + ret = wc_DhPubKeyToDer(key, tmp2, &idx); + } + + /* Verify export matches original */ + if (ret <= 0 || bytes != idx || XMEMCMP(tmp, tmp2, bytes) != 0) { + ERROR_OUT(-8134, done); } #ifdef WOLFSSL_SMALL_STACK @@ -16698,37 +16724,36 @@ WOLFSSL_TEST_SUBROUTINE int dh_test(void) #else ret = wc_DhSetKey(key, dh_p, sizeof(dh_p), dh_g, sizeof(dh_g)); if (ret != 0) { - ERROR_OUT(-8123, done); + ERROR_OUT(-8121, done); } -#endif - +#endif /* !NO_ASN */ privSz = DH_TEST_BUF_SIZE; pubSz = DH_TEST_BUF_SIZE; ret = wc_DhExportKeyPair(key, priv, &privSz, pub, &pubSz); if (ret != 0) { - ERROR_OUT(-8124, done); + ERROR_OUT(-8122, done); } ret = wc_DhImportKeyPair(key2, priv, privSz, pub, pubSz); if (ret != 0) { ERROR_OUT(-8125, done); } -#endif /* WOLFSSL_DH_EXTRA */ +#endif /* WOLFSSL_DH_EXTRA && !NO_FILESYSTEM && !FIPS <= 2 */ #ifndef WC_NO_RNG ret = dh_generate_test(&rng); if (ret != 0) - ERROR_OUT(-8126, done); + ERROR_OUT(-8123, done); ret = dh_fips_generate_test(&rng); if (ret != 0) - ERROR_OUT(-8127, done); + ERROR_OUT(-8124, done); #endif /* !WC_NO_RNG */ #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) ret = dh_test_check_pubvalue(); if (ret != 0) - ERROR_OUT(-8128, done); + ERROR_OUT(-8125, done); #endif #ifndef WC_NO_RNG @@ -16736,17 +16761,17 @@ WOLFSSL_TEST_SUBROUTINE int dh_test(void) #ifdef HAVE_FFDHE_2048 ret = dh_ffdhe_test(&rng, wc_Dh_ffdhe2048_Get()); if (ret != 0) - ERROR_OUT(-8129, done); + ERROR_OUT(-8126, done); #endif #ifdef HAVE_FFDHE_3072 ret = dh_ffdhe_test(&rng, wc_Dh_ffdhe3072_Get()); if (ret != 0) - ERROR_OUT(-8130, done); + ERROR_OUT(-8127, done); #endif #ifdef HAVE_FFDHE_4096 ret = dh_ffdhe_test(&rng, wc_Dh_ffdhe4096_Get()); if (ret != 0) - ERROR_OUT(-8131, done); + ERROR_OUT(-8128, done); #endif #endif /* !WC_NO_RNG */ @@ -16759,7 +16784,7 @@ WOLFSSL_TEST_SUBROUTINE int dh_test(void) ret = wc_DhSetCheckKey(key, dh_p, sizeof(dh_p), dh_g, sizeof(dh_g), NULL, 0, 0, &rng); if (ret != 0) - ERROR_OUT(-8132, done); + ERROR_OUT(-8129, done); keyInit = 1; /* DhSetCheckKey also initializes the key, free it */ #endif