Make a bunch of PKCS#8 improvements.
- Add doxygen documentation for wc_GetPkcs8TraditionalOffset, wc_CreatePKCS8Key, wc_EncryptPKCS8Key, and wc_DecryptPKCS8Key. - Add a new API function, wc_CreateEncryptedPKCS8Key, which handles both creation of an unencrypted PKCS#8 key and the subsequent encrypting of said key. This is a wrapper around TraditionalEnc, which does the same thing. This may become a first-class function at some point (i.e. not a wrapper). TraditionalEnc is left as is since it is used in the wild. - Added a unit test which exercises wc_CreateEncryptedPKCS8Key and wc_DecryptPKCS8Key. Testing wc_CreateEncryptedPKCS8Key inherently also tests TraditionalEnc, wc_CreatePKCS8Key, and wc_EncryptPKCS8Key. - Modified wc_EncryptPKCS8Key to be able to return the required output buffer size via LENGTH_ONLY_E idiom. - Added parameter checking to wc_EncryptPKCS8Key and wc_DecryptPKCS8Key.
This commit is contained in:
parent
2923d812bd
commit
b3401bd102
@ -1629,3 +1629,245 @@ WOLFSSL_API int wc_GetCTC_HashOID(int type);
|
||||
*/
|
||||
WOLFSSL_API void wc_SetCert_Free(Cert* cert);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function finds the beginning of the traditional private key
|
||||
inside a PKCS#8 unencrypted buffer.
|
||||
|
||||
\return Length of traditional private key on success.
|
||||
\return Negative values on failure.
|
||||
|
||||
\param input Buffer containing unencrypted PKCS#8 private key.
|
||||
\param inOutIdx Index into the input buffer. On input, it should be a byte
|
||||
offset to the beginning of the the PKCS#8 buffer. On output, it will be the
|
||||
byte offset to the traditional private key within the input buffer.
|
||||
\param sz The number of bytes in the input buffer.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
byte* pkcs8Buf; // Buffer containing PKCS#8 key.
|
||||
word32 idx = 0;
|
||||
word32 sz; // Size of pkcs8Buf.
|
||||
...
|
||||
ret = wc_GetPkcs8TraditionalOffset(pkcs8Buf, &idx, sz);
|
||||
// pkcs8Buf + idx is now the beginning of the traditional private key bytes.
|
||||
\endcode
|
||||
|
||||
\sa wc_CreatePKCS8Key
|
||||
\sa wc_EncryptPKCS8Key
|
||||
\sa wc_DecryptPKCS8Key
|
||||
\sa wc_CreateEncryptedPKCS8Key
|
||||
*/
|
||||
WOLFSSL_API int wc_GetPkcs8TraditionalOffset(byte* input,
|
||||
word32* inOutIdx, word32 sz);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function takes in a DER private key and converts it to PKCS#8
|
||||
format. Also used in creating PKCS#12 shrouded key bags. See RFC 5208.
|
||||
|
||||
\return The size of the PKCS#8 key placed into out on success.
|
||||
\return LENGTH_ONLY_E if out is NULL, with required output buffer size in
|
||||
outSz.
|
||||
\return Other negative values on failure.
|
||||
|
||||
\param out Buffer to place result in. If NULL, required out buffer size
|
||||
returned in outSz.
|
||||
\param outSz Size of out buffer.
|
||||
\param key Buffer with traditional DER key.
|
||||
\param keySz Size of key buffer.
|
||||
\param algoID Algorithm ID (e.g. RSAk).
|
||||
\param curveOID ECC curve OID if used. Should be NULL for RSA keys.
|
||||
\param oidSz Size of curve OID. Is set to 0 if curveOID is NULL.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
ecc_key eccKey; // wolfSSL ECC key object.
|
||||
byte* der; // DER-encoded ECC key.
|
||||
word32 derSize; // Size of der.
|
||||
const byte* curveOid = NULL; // OID of curve used by eccKey.
|
||||
word32 curveOidSz = 0; // Size of curve OID.
|
||||
byte* pkcs8; // Output buffer for PKCS#8 key.
|
||||
word32 pkcs8Sz; // Size of output buffer.
|
||||
|
||||
derSize = wc_EccKeyDerSize(&eccKey, 1);
|
||||
...
|
||||
derSize = wc_EccKeyToDer(&eccKey, der, derSize);
|
||||
...
|
||||
ret = wc_ecc_get_oid(eccKey.dp->oidSum, &curveOid, &curveOidSz);
|
||||
...
|
||||
ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, der,
|
||||
derSize, ECDSAk, curveOid, curveOidSz); // Get size needed in pkcs8Sz.
|
||||
...
|
||||
ret = wc_CreatePKCS8Key(pkcs8, &pkcs8Sz, der,
|
||||
derSize, ECDSAk, curveOid, curveOidSz);
|
||||
\endcode
|
||||
|
||||
\sa wc_GetPkcs8TraditionalOffset
|
||||
\sa wc_EncryptPKCS8Key
|
||||
\sa wc_DecryptPKCS8Key
|
||||
\sa wc_CreateEncryptedPKCS8Key
|
||||
*/
|
||||
WOLFSSL_API int wc_CreatePKCS8Key(byte* out, word32* outSz,
|
||||
byte* key, word32 keySz, int algoID, const byte* curveOID,
|
||||
word32 oidSz);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function takes in an unencrypted PKCS#8 DER key (e.g. one
|
||||
created by wc_CreatePKCS8Key) and converts it to PKCS#8 encrypted format.
|
||||
The resulting encrypted key can be decrypted using wc_DecryptPKCS8Key. See
|
||||
RFC 5208.
|
||||
|
||||
\return The size of the encrypted key placed in out on success.
|
||||
\return LENGTH_ONLY_E if out is NULL, with required output buffer size in
|
||||
outSz.
|
||||
\return Other negative values on failure.
|
||||
|
||||
\param key Buffer with traditional DER key.
|
||||
\param keySz Size of key buffer.
|
||||
\param out Buffer to place result in. If NULL, required out buffer size
|
||||
returned in outSz.
|
||||
\param outSz Size of out buffer.
|
||||
\param password The password to use for the password-based encryption
|
||||
algorithm.
|
||||
\param passwordSz The length of the password (not including the NULL
|
||||
terminator).
|
||||
\param vPKCS The PKCS version to use. Can be 1 for PKCS12 or PKCS5.
|
||||
\param pbeOid The OID of the PBE scheme to use (e.g. PBES2 or one of the
|
||||
OIDs for PBES1 in RFC 2898 A.3).
|
||||
\param encAlgId The encryption algorithm ID to use (e.g. AES256CBCb).
|
||||
\param salt The salt buffer to use. If NULL, a random salt will be used.
|
||||
\param saltSz The length of the salt buffer. Can be 0 if passing NULL for
|
||||
salt.
|
||||
\param itt The number of iterations to use for the KDF.
|
||||
\param rng A pointer to an initialized WC_RNG object.
|
||||
\param heap A pointer to the heap used for dynamic allocation. Can be NULL.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
byte* pkcs8; // Unencrypted PKCS#8 key.
|
||||
word32 pkcs8Sz; // Size of pkcs8.
|
||||
byte* pkcs8Enc; // Encrypted PKCS#8 key.
|
||||
word32 pkcs8EncSz; // Size of pkcs8Enc.
|
||||
const char* password; // Password to use for encryption.
|
||||
int passwordSz; // Length of password (not including NULL terminator).
|
||||
WC_RNG rng;
|
||||
|
||||
// The following produces an encrypted version of pkcs8 in pkcs8Enc. The
|
||||
// encryption uses password-based encryption scheme 2 (PBE2) from PKCS#5 and
|
||||
// the AES cipher in CBC mode with a 256-bit key. See RFC 8018 for more on
|
||||
// PKCS#5.
|
||||
ret = wc_EncryptPKCS8Key(pkcs8, pkcs8Sz, pkcs8Enc, &pkcs8EncSz, password,
|
||||
passwordSz, PKCS5, PBES2, AES256CBCb, NULL, 0,
|
||||
WC_PKCS12_ITT_DEFAULT, &rng, NULL);
|
||||
\endcode
|
||||
|
||||
\sa wc_GetPkcs8TraditionalOffset
|
||||
\sa wc_CreatePKCS8Key
|
||||
\sa wc_DecryptPKCS8Key
|
||||
\sa wc_CreateEncryptedPKCS8Key
|
||||
*/
|
||||
WOLFSSL_API int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out,
|
||||
word32* outSz, const char* password, int passwordSz, int vPKCS,
|
||||
int pbeOid, int encAlgId, byte* salt, word32 saltSz, int itt,
|
||||
WC_RNG* rng, void* heap);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function takes an encrypted PKCS#8 DER key and decrypts it to
|
||||
PKCS#8 unencrypted DER. Undoes the encryption done by wc_EncryptPKCS8Key.
|
||||
See RFC5208. The input buffer is overwritten with the decrypted data.
|
||||
|
||||
\return The length of the decrypted buffer on success.
|
||||
\return Negative values on failure.
|
||||
|
||||
\param input On input, buffer containing encrypted PKCS#8 key. On successful
|
||||
output, contains the decrypted key.
|
||||
\param sz Size of the input buffer.
|
||||
\param password The password used to encrypt the key.
|
||||
\param passwordSz The length of the password (not including NULL
|
||||
terminator).
|
||||
|
||||
_Example_
|
||||
\code
|
||||
byte* pkcs8Enc; // Encrypted PKCS#8 key made with wc_EncryptPKCS8Key.
|
||||
word32 pkcs8EncSz; // Size of pkcs8Enc.
|
||||
const char* password; // Password to use for decryption.
|
||||
int passwordSz; // Length of password (not including NULL terminator).
|
||||
|
||||
ret = wc_DecryptPKCS8Key(pkcs8Enc, pkcs8EncSz, password, passwordSz);
|
||||
\endcode
|
||||
|
||||
\sa wc_GetPkcs8TraditionalOffset
|
||||
\sa wc_CreatePKCS8Key
|
||||
\sa wc_EncryptPKCS8Key
|
||||
\sa wc_CreateEncryptedPKCS8Key
|
||||
*/
|
||||
WOLFSSL_API int wc_DecryptPKCS8Key(byte* input, word32 sz, const char* password,
|
||||
int passwordSz);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function takes a traditional, DER key, converts it to PKCS#8
|
||||
format, and encrypts it. It uses wc_CreatePKCS8Key and wc_EncryptPKCS8Key
|
||||
to do this.
|
||||
|
||||
\return The size of the encrypted key placed in out on success.
|
||||
\return LENGTH_ONLY_E if out is NULL, with required output buffer size in
|
||||
outSz.
|
||||
\return Other negative values on failure.
|
||||
|
||||
\param key Buffer with traditional DER key.
|
||||
\param keySz Size of key buffer.
|
||||
\param out Buffer to place result in. If NULL, required out buffer size
|
||||
returned in outSz.
|
||||
\param outSz Size of out buffer.
|
||||
\param password The password to use for the password-based encryption
|
||||
algorithm.
|
||||
\param passwordSz The length of the password (not including the NULL
|
||||
terminator).
|
||||
\param vPKCS The PKCS version to use. Can be 1 for PKCS12 or PKCS5.
|
||||
\param pbeOid The OID of the PBE scheme to use (e.g. PBES2 or one of the
|
||||
OIDs for PBES1 in RFC 2898 A.3).
|
||||
\param encAlgId The encryption algorithm ID to use (e.g. AES256CBCb).
|
||||
\param salt The salt buffer to use. If NULL, a random salt will be used.
|
||||
\param saltSz The length of the salt buffer. Can be 0 if passing NULL for
|
||||
salt.
|
||||
\param itt The number of iterations to use for the KDF.
|
||||
\param rng A pointer to an initialized WC_RNG object.
|
||||
\param heap A pointer to the heap used for dynamic allocation. Can be NULL.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
byte* key; // Traditional private key (DER formatted).
|
||||
word32 keySz; // Size of key.
|
||||
byte* pkcs8Enc; // Encrypted PKCS#8 key.
|
||||
word32 pkcs8EncSz; // Size of pkcs8Enc.
|
||||
const char* password; // Password to use for encryption.
|
||||
int passwordSz; // Length of password (not including NULL terminator).
|
||||
WC_RNG rng;
|
||||
|
||||
// The following produces an encrypted, PKCS#8 version of key in pkcs8Enc.
|
||||
// The encryption uses password-based encryption scheme 2 (PBE2) from PKCS#5
|
||||
// and the AES cipher in CBC mode with a 256-bit key. See RFC 8018 for more
|
||||
// on PKCS#5.
|
||||
ret = wc_CreateEncryptedPKCS8Key(key, keySz, pkcs8Enc, &pkcs8EncSz,
|
||||
password, passwordSz, PKCS5, PBES2, AES256CBCb, NULL, 0,
|
||||
WC_PKCS12_ITT_DEFAULT, &rng, NULL);
|
||||
\endcode
|
||||
|
||||
\sa wc_GetPkcs8TraditionalOffset
|
||||
\sa wc_CreatePKCS8Key
|
||||
\sa wc_EncryptPKCS8Key
|
||||
\sa wc_DecryptPKCS8Key
|
||||
*/
|
||||
WOLFSSL_API int wc_CreateEncryptedPKCS8Key(byte* key, word32 keySz, byte* out,
|
||||
word32* outSz, const char* password, int passwordSz, int vPKCS,
|
||||
int pbeOid, int encAlgId, byte* salt, word32 saltSz, int itt,
|
||||
WC_RNG* rng, void* heap);
|
||||
|
45
tests/api.c
45
tests/api.c
@ -39640,6 +39640,50 @@ static void test_wolfSSL_CRYPTO_memcmp(void)
|
||||
| wolfCrypt ASN
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static void test_wc_CreateEncryptedPKCS8Key(void)
|
||||
{
|
||||
#if defined(HAVE_PKCS8) && !defined(NO_PWDBASED) && defined(WOLFSSL_AES_256) \
|
||||
&& !defined(NO_AES_CBC) && !defined(NO_RSA) && !defined(NO_SHA)
|
||||
WC_RNG rng;
|
||||
byte* encKey = NULL;
|
||||
word32 encKeySz = 0;
|
||||
word32 decKeySz = 0;
|
||||
const char password[] = "Lorem ipsum dolor sit amet";
|
||||
word32 passwordSz = (word32)XSTRLEN(password);
|
||||
word32 tradIdx = 0;
|
||||
|
||||
printf(testingFmt, "test_wc_CreateEncryptedPKCS8Key");
|
||||
|
||||
AssertIntEQ(wc_InitRng(&rng), 0);
|
||||
/* Call with NULL for out buffer to get necessary length. */
|
||||
AssertIntEQ(wc_CreateEncryptedPKCS8Key((byte*)server_key_der_2048,
|
||||
sizeof_server_key_der_2048, NULL, &encKeySz, password, passwordSz,
|
||||
PKCS5, PBES2, AES256CBCb, NULL, 0, WC_PKCS12_ITT_DEFAULT, &rng, NULL),
|
||||
LENGTH_ONLY_E);
|
||||
AssertNotNull(encKey = (byte*)XMALLOC(encKeySz, HEAP_HINT,
|
||||
DYNAMIC_TYPE_TMP_BUFFER));
|
||||
/* Call with the allocated out buffer. */
|
||||
AssertIntGT(wc_CreateEncryptedPKCS8Key((byte*)server_key_der_2048,
|
||||
sizeof_server_key_der_2048, encKey, &encKeySz, password, passwordSz,
|
||||
PKCS5, PBES2, AES256CBCb, NULL, 0, WC_PKCS12_ITT_DEFAULT, &rng, NULL),
|
||||
0);
|
||||
/* Decrypt the encrypted PKCS8 key we just made. */
|
||||
AssertIntGT((decKeySz = wc_DecryptPKCS8Key(encKey, encKeySz, password,
|
||||
passwordSz)), 0);
|
||||
/* encKey now holds the decrypted key (decrypted in place). */
|
||||
AssertIntGT(wc_GetPkcs8TraditionalOffset(encKey, &tradIdx, decKeySz), 0);
|
||||
/* Check that the decrypted key matches the key prior to encryption. */
|
||||
AssertIntEQ(XMEMCMP(encKey + tradIdx, server_key_der_2048,
|
||||
sizeof_server_key_der_2048), 0);
|
||||
|
||||
if (encKey != NULL)
|
||||
XFREE(encKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wc_FreeRng(&rng);
|
||||
|
||||
printf(resultFmt, passed);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_wc_GetPkcs8TraditionalOffset(void)
|
||||
{
|
||||
#if !defined(NO_ASN) && !defined(NO_FILESYSTEM) && defined(HAVE_PKCS8)
|
||||
@ -45238,6 +45282,7 @@ void ApiTest(void)
|
||||
#endif
|
||||
|
||||
/* wolfCrypt ASN tests */
|
||||
test_wc_CreateEncryptedPKCS8Key();
|
||||
test_wc_GetPkcs8TraditionalOffset();
|
||||
test_wc_SetSubjectRaw();
|
||||
test_wc_GetSubjectRaw();
|
||||
|
@ -2852,10 +2852,6 @@ int ToTraditional(byte* input, word32 sz)
|
||||
|
||||
#if defined(HAVE_PKCS8) && !defined(NO_CERTS)
|
||||
|
||||
/* find beginning of traditional key inside PKCS#8 unencrypted buffer
|
||||
* return traditional length on success, with inOutIdx at beginning of
|
||||
* traditional
|
||||
* return negative on failure/error */
|
||||
int wc_GetPkcs8TraditionalOffset(byte* input, word32* inOutIdx, word32 sz)
|
||||
{
|
||||
int length;
|
||||
@ -2869,33 +2865,6 @@ int wc_GetPkcs8TraditionalOffset(byte* input, word32* inOutIdx, word32 sz)
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
*
|
||||
* out buffer to place result in
|
||||
* outSz size of out buffer
|
||||
* key buffer with DER key
|
||||
* keySz size of key buffer
|
||||
* algoID algorithm ID i.e. RSAk
|
||||
* curveOID ECC curve oid if used. Should be NULL for RSA keys.
|
||||
* oidSz size of curve oid. Is set to 0 if curveOID is NULL.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
@ -3506,234 +3475,16 @@ static int Pkcs8Pad(byte* buf, int sz, int blockSz)
|
||||
#ifdef HAVE_PKCS8
|
||||
|
||||
/*
|
||||
* Used when creating PKCS12 shrouded key bags
|
||||
* vPKCS is the version of PKCS to use
|
||||
* vAlgo is the algorithm version to use
|
||||
*
|
||||
* if salt is NULL a random number is generated
|
||||
*
|
||||
* returns the size of encrypted data on success
|
||||
* Equivalent to calling TraditionalEnc with the same parameters but with
|
||||
* encAlgId set to 0. This function must be kept alive because it's sometimes
|
||||
* part of the API (WOLFSSL_ASN_API).
|
||||
*/
|
||||
int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
|
||||
const char* password, int passwordSz, int vPKCS, int vAlgo,
|
||||
byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap)
|
||||
{
|
||||
int algoID = 0;
|
||||
byte* tmp;
|
||||
word32 tmpSz = 0;
|
||||
word32 sz;
|
||||
word32 seqSz;
|
||||
word32 inOutIdx = 0;
|
||||
word32 totalSz = 0;
|
||||
int version, id;
|
||||
int ret;
|
||||
int blockSz = 0;
|
||||
|
||||
const byte* curveOID = NULL;
|
||||
word32 oidSz = 0;
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
byte* saltTmp = NULL;
|
||||
byte* cbcIv = NULL;
|
||||
#else
|
||||
byte saltTmp[MAX_IV_SIZE];
|
||||
byte cbcIv[MAX_IV_SIZE];
|
||||
#endif
|
||||
|
||||
WOLFSSL_ENTER("UnTraditionalEnc()");
|
||||
|
||||
if (saltSz > MAX_SALT_SIZE)
|
||||
return ASN_PARSE_E;
|
||||
|
||||
|
||||
inOutIdx += MAX_SEQ_SZ; /* leave room for size of finished shroud */
|
||||
if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0) {
|
||||
WOLFSSL_MSG("Bad/Unsupported algorithm ID");
|
||||
return ASN_INPUT_E; /* Algo ID error */
|
||||
}
|
||||
|
||||
if (out != NULL) {
|
||||
if (*outSz < inOutIdx + MAX_ALGO_SZ + MAX_SALT_SIZE + MAX_SEQ_SZ + 1 +
|
||||
MAX_LENGTH_SZ + MAX_SHORT_SZ + 1)
|
||||
return BUFFER_E;
|
||||
|
||||
if (version == PKCS5v2) {
|
||||
WOLFSSL_MSG("PKCS5v2 Not supported yet\n");
|
||||
return ASN_VERSION_E;
|
||||
}
|
||||
|
||||
if (salt == NULL || saltSz == 0) {
|
||||
saltSz = 8;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (saltTmp == NULL)
|
||||
return MEMORY_E;
|
||||
#endif
|
||||
salt = saltTmp;
|
||||
|
||||
if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
|
||||
WOLFSSL_MSG("Error generating random salt");
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* leave room for a sequence (contains salt and iterations int) */
|
||||
inOutIdx += MAX_SEQ_SZ; sz = 0;
|
||||
inOutIdx += MAX_ALGO_SZ;
|
||||
|
||||
/* place salt in buffer */
|
||||
out[inOutIdx++] = ASN_OCTET_STRING; sz++;
|
||||
tmpSz = SetLength(saltSz, out + inOutIdx);
|
||||
inOutIdx += tmpSz; sz += tmpSz;
|
||||
XMEMCPY(out + inOutIdx, salt, saltSz);
|
||||
inOutIdx += saltSz; sz += saltSz;
|
||||
|
||||
/* place iteration count in buffer */
|
||||
ret = SetShortInt(out, &inOutIdx, itt, *outSz);
|
||||
if (ret < 0) {
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
sz += (word32)ret;
|
||||
|
||||
/* wind back index and set sequence then clean up buffer */
|
||||
inOutIdx -= (sz + MAX_SEQ_SZ);
|
||||
tmpSz = SetSequence(sz, out + inOutIdx);
|
||||
XMEMMOVE(out + inOutIdx + tmpSz, out + inOutIdx + MAX_SEQ_SZ, sz);
|
||||
totalSz += tmpSz + sz; sz += tmpSz;
|
||||
|
||||
/* add in algo ID */
|
||||
inOutIdx -= MAX_ALGO_SZ;
|
||||
tmpSz = SetAlgoID(id, out + inOutIdx, oidPBEType, sz);
|
||||
XMEMMOVE(out + inOutIdx + tmpSz, out + inOutIdx + MAX_ALGO_SZ, sz);
|
||||
totalSz += tmpSz; inOutIdx += tmpSz + sz;
|
||||
|
||||
/* octet string containing encrypted key */
|
||||
out[inOutIdx++] = ASN_OCTET_STRING; totalSz++;
|
||||
}
|
||||
|
||||
/* check key type and get OID if ECC */
|
||||
if ((ret = wc_GetKeyOID(key, keySz, &curveOID, &oidSz, &algoID, heap))< 0) {
|
||||
WOLFSSL_MSG("Error getting key OID");
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PKCS#8 wrapping around key */
|
||||
if (wc_CreatePKCS8Key(NULL, &tmpSz, key, keySz, algoID, curveOID, oidSz)
|
||||
!= LENGTH_ONLY_E) {
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
/* check if should return max size */
|
||||
if (out == NULL) {
|
||||
/* account for salt size */
|
||||
if (salt == NULL || saltSz == 0) {
|
||||
tmpSz += MAX_SALT_SIZE;
|
||||
}
|
||||
else {
|
||||
tmpSz += saltSz;
|
||||
}
|
||||
|
||||
/* plus 3 for tags */
|
||||
*outSz = tmpSz + MAX_ALGO_SZ + MAX_LENGTH_SZ +MAX_LENGTH_SZ + MAX_SEQ_SZ
|
||||
+ MAX_LENGTH_SZ + MAX_SEQ_SZ + 3;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return LENGTH_ONLY_E;
|
||||
}
|
||||
|
||||
/* reserve buffer for crypto and make sure it supports full blocks */
|
||||
tmp = (byte*)XMALLOC(tmpSz + (blockSz-1), heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (tmp == NULL) {
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
if ((ret = wc_CreatePKCS8Key(tmp, &tmpSz, key, keySz, algoID, curveOID,
|
||||
oidSz)) < 0) {
|
||||
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
WOLFSSL_MSG("Error wrapping key with PKCS#8");
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
tmpSz = ret;
|
||||
|
||||
/* adjust size to pad */
|
||||
tmpSz = Pkcs8Pad(tmp, tmpSz, blockSz);
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (cbcIv == NULL) {
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return MEMORY_E;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* encrypt PKCS#8 wrapped key */
|
||||
if ((ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id,
|
||||
tmp, tmpSz, version, cbcIv, 1, 0)) < 0) {
|
||||
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
WOLFSSL_MSG("Error encrypting key");
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (cbcIv != NULL)
|
||||
XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
return ret; /* encryption failure */
|
||||
}
|
||||
totalSz += tmpSz;
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
if (saltTmp != NULL)
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (cbcIv != NULL)
|
||||
XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
|
||||
if (*outSz < inOutIdx + tmpSz + MAX_LENGTH_SZ) {
|
||||
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
/* set length of key and copy over encrypted key */
|
||||
seqSz = SetLength(tmpSz, out + inOutIdx);
|
||||
inOutIdx += seqSz; totalSz += seqSz;
|
||||
XMEMCPY(out + inOutIdx, tmp, tmpSz);
|
||||
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
/* set total size at beginning */
|
||||
sz = SetSequence(totalSz, out);
|
||||
XMEMMOVE(out + sz, out + MAX_SEQ_SZ, totalSz);
|
||||
|
||||
(void)rng;
|
||||
|
||||
return totalSz + sz;
|
||||
return TraditionalEnc(key, keySz, out, outSz, password, passwordSz,
|
||||
vPKCS, vAlgo, 0, salt, saltSz, itt, rng, heap);
|
||||
}
|
||||
|
||||
static int GetAlgoV2(int encAlgId, const byte** oid, int *len, int* id,
|
||||
@ -3775,37 +3526,7 @@ static int GetAlgoV2(int encAlgId, const byte** oid, int *len, int* id,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PKCS#8 encryption from RFC 5208
|
||||
* This function takes in an unencrypted PKCS#8 DER key and converts it to
|
||||
* PKCS#8 encrypted format. The resulting encrypted key can be decrypted using
|
||||
* wc_DecryptPKCS8Key.
|
||||
*
|
||||
* EncryptedPrivateKeyInfo ::= SEQUENCE {
|
||||
* encryptionAlgorithm EncryptionAlgorithmIdentifier,
|
||||
* encryptedData EncryptedData }
|
||||
* EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||
* EncryptedData ::= OCTET STRING
|
||||
*
|
||||
* key DER buffer containing the unencrypted PKCS#8 key.
|
||||
* keySz The size of the key buffer.
|
||||
* out The buffer to place the encrypted key in.
|
||||
* outSz The size of the out buffer.
|
||||
* password The password to use for the password-based encryption algorithm.
|
||||
* passwordSz The length of the password (not including the NULL terminator).
|
||||
* vPKCS The PKCS version to use. Can be 1 for PKCS12 or PKCS5.
|
||||
* pbeOid The OID of the PBE scheme to use (e.g. PBES2 or one of the OIDs
|
||||
for PBES1 in RFC 2898 A.3)
|
||||
* encAlgId The encryption algorithm ID to use (e.g. AES256CBCb).
|
||||
* salt The salt buffer to use. If NULL, a random salt will be used.
|
||||
* saltSz The length of the salt buffer. Can be 0 if passing NULL for salt.
|
||||
* itt The number of iterations to use for the KDF.
|
||||
* rng A pointer to an initialized WC_RNG object.
|
||||
* heap A pointer to the heap use for dynamic allocation. Can be NULL.
|
||||
*
|
||||
* Returns the size of the encrypted key placed in out. In error cases, returns
|
||||
* negative values.
|
||||
*/
|
||||
int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32 outSz,
|
||||
int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz,
|
||||
const char* password, int passwordSz, int vPKCS, int pbeOid,
|
||||
int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng,
|
||||
void* heap)
|
||||
@ -3815,6 +3536,7 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32 outSz,
|
||||
#else
|
||||
byte saltTmp[MAX_SALT_SIZE];
|
||||
#endif
|
||||
int genSalt = 0;
|
||||
int ret = 0;
|
||||
int version = 0;
|
||||
int pbeId = 0;
|
||||
@ -3837,27 +3559,20 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32 outSz,
|
||||
|
||||
WOLFSSL_ENTER("wc_EncryptPKCS8Key");
|
||||
|
||||
ret = CheckAlgo(vPKCS, pbeOid, &pbeId, &version, &blockSz);
|
||||
if (ret == 0 && (salt == NULL || saltSz == 0)) {
|
||||
saltSz = 8;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (saltTmp == NULL)
|
||||
ret = MEMORY_E;
|
||||
#endif
|
||||
salt = saltTmp;
|
||||
|
||||
if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
|
||||
WOLFSSL_MSG("Error generating random salt");
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
}
|
||||
if (key == NULL || outSz == NULL || password == NULL) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (ret == 0 && version == PKCS5v2)
|
||||
if (ret == 0) {
|
||||
ret = CheckAlgo(vPKCS, pbeOid, &pbeId, &version, &blockSz);
|
||||
}
|
||||
if (ret == 0 && (salt == NULL || saltSz == 0)) {
|
||||
genSalt = 1;
|
||||
saltSz = 8;
|
||||
}
|
||||
if (ret == 0 && version == PKCS5v2) {
|
||||
ret = GetAlgoV2(encAlgId, &encOid, &encOidSz, &pbeId, &blockSz);
|
||||
|
||||
}
|
||||
if (ret == 0) {
|
||||
padSz = (blockSz - (keySz & (blockSz - 1))) & (blockSz - 1);
|
||||
/* inner = OCT salt INT itt */
|
||||
@ -3882,10 +3597,19 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32 outSz,
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* outer = SEQ [ pbe ] OCT encrypted_PKCS#8_key */
|
||||
/* outerLen = length of PBE encoding + octet string data */
|
||||
/* Plus 2 for tag and length for pbe */
|
||||
outerLen = 2 + pbeLen;
|
||||
outerLen += SetOctetString(keySz + padSz, out);
|
||||
/* Octet string tag, length */
|
||||
outerLen += 1 + SetLength(keySz + padSz, NULL);
|
||||
/* Octet string bytes */
|
||||
outerLen += keySz + padSz;
|
||||
if (out == NULL) {
|
||||
/* Sequence tag, length */
|
||||
*outSz = 1 + SetLength(outerLen, NULL) + outerLen;
|
||||
return LENGTH_ONLY_E;
|
||||
}
|
||||
SetOctetString(keySz + padSz, out);
|
||||
|
||||
idx += SetSequence(outerLen, out + idx);
|
||||
|
||||
@ -3896,8 +3620,26 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32 outSz,
|
||||
XMEMSET(out + encIdx + keySz, padSz, padSz);
|
||||
keySz += padSz;
|
||||
}
|
||||
|
||||
if (genSalt == 1) {
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (saltTmp == NULL) {
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
salt = saltTmp;
|
||||
if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
|
||||
WOLFSSL_MSG("Error generating random salt");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, pbeId,
|
||||
out + encIdx, keySz, version, cbcIv, 1, 0);
|
||||
out + encIdx, keySz, version, cbcIv, 1, 0);
|
||||
}
|
||||
if (ret == 0) {
|
||||
if (version != PKCS5v2) {
|
||||
@ -3924,7 +3666,7 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32 outSz,
|
||||
idx += SetSequence(innerLen, out + idx);
|
||||
idx += SetOctetString(saltSz, out + idx);
|
||||
XMEMCPY(out + idx, salt, saltSz); idx += saltSz;
|
||||
ret = SetShortInt(out, &idx, itt, outSz);
|
||||
ret = SetShortInt(out, &idx, itt, *outSz);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
}
|
||||
@ -3958,14 +3700,6 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32 outSz,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PKCS#8 decryption from RFC 5208
|
||||
*
|
||||
* NOTE: input buffer is overwritten with decrypted data!
|
||||
*
|
||||
* This function takes an encrypted PKCS#8 DER key and decrypts it to PKCS#8
|
||||
* unencrypted DER. Undoes the encryption done by wc_EncryptPKCS8Key. Returns
|
||||
* the length of the decrypted buffer or a negative value if there was an error.
|
||||
*/
|
||||
int wc_DecryptPKCS8Key(byte* input, word32 sz, const char* password,
|
||||
int passwordSz)
|
||||
{
|
||||
@ -3973,6 +3707,10 @@ int wc_DecryptPKCS8Key(byte* input, word32 sz, const char* password,
|
||||
int length;
|
||||
word32 inOutIdx = 0;
|
||||
|
||||
if (input == NULL || password == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
@ -4001,7 +3739,9 @@ int wc_DecryptPKCS8Key(byte* input, word32 sz, const char* password,
|
||||
}
|
||||
|
||||
/* Takes an unencrypted, traditional DER-encoded key and converts it to a PKCS#8
|
||||
* encrypted key. */
|
||||
* encrypted key. If out is not NULL, it will hold the encrypted key. If it's
|
||||
* NULL, LENGTH_ONLY_E will be returned and outSz will have the required out
|
||||
* buffer size. */
|
||||
int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
|
||||
const char* password, int passwordSz, int vPKCS, int vAlgo,
|
||||
int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng,
|
||||
@ -4040,7 +3780,7 @@ int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_EncryptPKCS8Key(pkcs8Key, pkcs8KeySz, out, *outSz, password,
|
||||
ret = wc_EncryptPKCS8Key(pkcs8Key, pkcs8KeySz, out, outSz, password,
|
||||
passwordSz, vPKCS, vAlgo, encAlgId, salt, saltSz, itt, rng, heap);
|
||||
}
|
||||
|
||||
@ -4054,6 +3794,17 @@ int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Same as TraditionalEnc, but in the public API. */
|
||||
int wc_CreateEncryptedPKCS8Key(byte* key, word32 keySz, byte* out,
|
||||
word32* outSz, const char* password, int passwordSz, int vPKCS,
|
||||
int pbeOid, int encAlgId, byte* salt, word32 saltSz, int itt,
|
||||
WC_RNG* rng, void* heap)
|
||||
{
|
||||
return TraditionalEnc(key, keySz, out, outSz, password, passwordSz, vPKCS,
|
||||
pbeOid, encAlgId, salt, saltSz, itt, rng, heap);
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_PKCS8 */
|
||||
|
||||
#if defined(HAVE_PKCS8) || defined(HAVE_PKCS12)
|
||||
|
@ -593,10 +593,13 @@ WOLFSSL_API int wc_GetCTC_HashOID(int type);
|
||||
WOLFSSL_API int wc_GetPkcs8TraditionalOffset(byte* input,
|
||||
word32* inOutIdx, word32 sz);
|
||||
WOLFSSL_API int wc_CreatePKCS8Key(byte* out, word32* outSz,
|
||||
byte* key, word32 keySz, int algoID, const byte* curveOID, word32 oidSz);
|
||||
WOLFSSL_API int wc_EncryptPKCS8Key(byte*, word32, byte*, word32, const char*,
|
||||
byte* key, word32 keySz, int algoID, const byte* curveOID,
|
||||
word32 oidSz);
|
||||
WOLFSSL_API int wc_EncryptPKCS8Key(byte*, word32, byte*, word32*, const char*,
|
||||
int, int, int, int, byte*, word32, int, WC_RNG*, void*);
|
||||
WOLFSSL_API int wc_DecryptPKCS8Key(byte*, word32, const char*, int);
|
||||
WOLFSSL_API int wc_CreateEncryptedPKCS8Key(byte*, word32, byte*, word32*,
|
||||
const char*, int, int, int, int, byte*, word32, int, WC_RNG*, void*);
|
||||
|
||||
#ifndef NO_ASN_TIME
|
||||
/* Time */
|
||||
|
Loading…
x
Reference in New Issue
Block a user