From 72d11e19cd7fdfc759e0c0bcac5a775604dd5a33 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 29 Mar 2017 16:14:34 -0600 Subject: [PATCH] add create PKCS8 key --- wolfcrypt/src/asn.c | 153 ++++++++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/asn.h | 5 ++ 2 files changed, 158 insertions(+) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 3114ef915..10bb3dc15 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -1934,6 +1934,159 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt, } +/* PKCS#8 from RFC 5208 + * This function takes in a DER key and converts it to PKCS#8 format. Used + * in creating PKCS#12 shrouded key bags. + * Reverse of ToTraditional + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes optional + * } + * Version ::= INTEGER + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * PrivateKey ::= OCTET STRING + * + * Returns the size of PKCS#8 placed into out. In error cases returns negative + * values. + */ +int wc_CreatePKCS8Key(byte* out, word32* outSz, byte* key, word32 keySz, + int algoID, const byte* curveOID, word32 oidSz) +{ + word32 keyIdx = 0; + word32 tmpSz = 0; + word32 sz; + + + /* If out is NULL then return the max size needed + * + 2 for ASN_OBJECT_ID and ASN_OCTET_STRING tags */ + if (out == NULL && outSz != NULL) { + *outSz = keySz + MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_ALGO_SZ + + MAX_LENGTH_SZ + MAX_LENGTH_SZ + 2; + + if (curveOID != NULL) + *outSz += oidSz + MAX_LENGTH_SZ + 1; + + WOLFSSL_MSG("Checking size of PKCS8"); + + return LENGTH_ONLY_E; + } + + WOLFSSL_ENTER("wc_CreatePKCS8Key()"); + + if (key == NULL || out == NULL || outSz == NULL) { + return BAD_FUNC_ARG; + } + + /* check the buffer has enough room for largest possible size */ + if (curveOID != NULL) { + if (*outSz < (keySz + MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_ALGO_SZ + + MAX_LENGTH_SZ + MAX_LENGTH_SZ + 3 + oidSz + MAX_LENGTH_SZ)) + return BUFFER_E; + } + else { + if (*outSz < (keySz + MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_ALGO_SZ + + MAX_LENGTH_SZ + MAX_LENGTH_SZ + 2)) + return BUFFER_E; + } + + /* PrivateKeyInfo ::= SEQUENCE */ + keyIdx += MAX_SEQ_SZ; /* save room for sequence */ + + /* version Version + * no header information just INTEGER */ + sz = SetMyVersion(PKCS8v0, out + keyIdx, 0); + tmpSz += sz; keyIdx += sz; + + /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier */ + sz = SetAlgoID(algoID, out + keyIdx, oidKeyType, 0); + tmpSz += sz; keyIdx += sz; + + /* privateKey PrivateKey * + * pkcs8 ecc uses slightly different format. Places curve oid in + * buffer */ + if (curveOID != NULL && oidSz > 0) { + out[keyIdx++] = ASN_OBJECT_ID; tmpSz++; + sz = SetLength(oidSz, out + keyIdx); + keyIdx += sz; tmpSz += sz; + XMEMCPY(out + keyIdx, curveOID, oidSz); + keyIdx += oidSz; tmpSz += keyIdx; + } + + out[keyIdx] = ASN_OCTET_STRING; + keyIdx++; tmpSz++; + + sz = SetLength(keySz, out + keyIdx); + keyIdx += sz; tmpSz += sz; + XMEMCPY(out + keyIdx, key, keySz); + tmpSz += keySz; + + /* attributes optional + * No attributes currently added */ + + /* rewind and add sequence */ + sz = SetSequence(tmpSz, out); + XMEMMOVE(out + sz, out + MAX_SEQ_SZ, tmpSz); + + return tmpSz + sz; +} + + +int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz, + int* algoID, void* heap) +{ + word32 tmpIdx = 0; + + #ifdef HAVE_ECC + ecc_key ecc; + #endif + + #ifndef NO_RSA + RsaKey rsa; + + wc_InitRsaKey(&rsa, heap); + if (wc_RsaPrivateKeyDecode(key, &tmpIdx, &rsa, keySz) == 0) { + *algoID = RSAk; + } + else { + WOLFSSL_MSG("Not RSA DER key"); + } + wc_FreeRsaKey(&rsa); + #endif /* NO_RSA */ + #ifdef HAVE_ECC + if (algoID == 0) { + tmpIdx = 0; + wc_ecc_init_ex(&ecc, heap, INVALID_DEVID); + if (wc_EccPrivateKeyDecode(key, &tmpIdx, &ecc, keySz) == 0) { + *algoID = ECDSAk; + + /* now find oid */ + if (wc_ecc_get_oid(ecc.dp->oidSum, curveOID, oidSz) < 0) { + WOLFSSL_MSG("Error getting ECC curve OID"); + wc_ecc_free(&ecc); + return BAD_FUNC_ARG; + } + } + else { + WOLFSSL_MSG("Not ECC DER key either"); + } + wc_ecc_free(&ecc); + } + #endif /* HAVE_ECC */ + + /* if flag is not set then is neither RSA or ECC key that could be + * found */ + if (*algoID == 0) { + WOLFSSL_MSG("Bad key DER or compile options"); + return BAD_FUNC_ARG; + } + + return 1; +} + + /* Remove Encrypted PKCS8 header, move beginning of traditional to beginning of input */ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index f1419a1d2..a75573939 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -134,6 +134,7 @@ enum Misc_ASN { MAX_KEY_SIZE = 64, /* MAX PKCS Key length */ PKCS5 = 5, /* PKCS oid tag */ PKCS5v2 = 6, /* PKCS #5 v2.0 */ + PKCS8v0 = 0, /* default PKCS#8 version */ PKCS12 = 12, /* PKCS #12 */ MAX_UNICODE_SZ = 256, ASN_BOOL_SIZE = 2, /* including type */ @@ -684,6 +685,10 @@ WOLFSSL_LOCAL int ToTraditionalInline(const byte* input, word32* inOutIdx, word32 length); WOLFSSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*,int); WOLFSSL_LOCAL int DecryptContent(byte* input, word32 sz,const char* psw,int pswSz); +WOLFSSL_LOCAL int wc_CreatePKCS8Key(byte* out, word32* outSz, + byte* key, word32 keySz, int algoID, const byte* curveOID, word32 oidSz); +WOLFSSL_LOCAL int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, + word32* oidSz, int* algoID, void* heap); typedef struct tm wolfssl_tm; #if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)