PKCS12 create function

This commit is contained in:
Jacob Barthelmeh
2017-01-20 19:11:25 -07:00
parent 2e1068f30c
commit c552de77f4
8 changed files with 1547 additions and 86 deletions
+92 -1
View File
@@ -14838,7 +14838,7 @@ static void ExternalFreeX509(WOLFSSL_X509* x509)
{
WOLFSSL_ENTER("wolfSSL_X509_get_der");
if (x509 == NULL || outSz == NULL)
if (x509 == NULL || x509->derCert == NULL || outSz == NULL)
return NULL;
*outSz = (int)x509->derCert->length;
@@ -16403,6 +16403,97 @@ WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12)
}
/* helper function to get DER buffer from WOLFSSL_EVP_PKEY */
static int wolfSSL_i2d_PrivateKey(WOLFSSL_EVP_PKEY* key, unsigned char** der)
{
*der = (unsigned char*)key->pkey.ptr;
return key->pkey_sz;
}
WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name,
WOLFSSL_EVP_PKEY* pkey, WOLFSSL_X509* cert,
WOLF_STACK_OF(WOLFSSL_X509)* ca,
int keyNID, int certNID, int itt, int macItt, int keyType)
{
WC_PKCS12* pkcs12;
WC_DerCertList* list = NULL;
word32 passSz = (word32)XSTRLEN(pass);
byte* keyDer;
word32 keyDerSz;
byte* certDer;
int certDerSz;
int ret;
WOLFSSL_ENTER("wolfSSL_PKCS12_create()");
if (pass == NULL || pkey == NULL || cert == NULL) {
WOLFSSL_LEAVE("wolfSSL_PKCS12_create()", BAD_FUNC_ARG);
return NULL;
}
if ((ret = wolfSSL_i2d_PrivateKey(pkey, &keyDer)) < 0) {
WOLFSSL_LEAVE("wolfSSL_PKCS12_create", ret);
return NULL;
}
keyDerSz = ret;
certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz);
if (certDer == NULL) {
return NULL;
}
if (ca != NULL) {
WC_DerCertList* cur;
unsigned long numCerts = ca->num;
byte* curDer;
int curDerSz = 0;
WOLFSSL_STACK* sk = ca;
while (numCerts > 0 && sk != NULL) {
cur = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList), NULL,
DYNAMIC_TYPE_PKCS);
if (cur == NULL) {
wc_FreeCertList(list, NULL);
return NULL;
}
curDer = (byte*)wolfSSL_X509_get_der(sk->data.x509, &curDerSz);
if (certDer == NULL || curDerSz < 0) {
wc_FreeCertList(list, NULL);
return NULL;
}
cur->buffer = (byte*)XMALLOC(curDerSz, NULL, DYNAMIC_TYPE_PKCS);
if (cur->buffer == NULL) {
wc_FreeCertList(list, NULL);
return NULL;
}
XMEMCPY(cur->buffer, curDer, curDerSz);
cur->bufferSz = curDerSz;
cur->next = list;
list = cur;
sk = sk->next;
numCerts--;
}
}
pkcs12 = wc_PKCS12_create(pass, passSz, name, keyDer, keyDerSz,
certDer, certDerSz, list, keyNID, certNID, itt, macItt,
keyType, NULL);
if (ca != NULL) {
wc_FreeCertList(list, NULL);
}
return pkcs12;
}
/* return 1 on success, 0 on failure */
int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, WOLF_STACK_OF(WOLFSSL_X509)** ca)
+57
View File
@@ -2523,11 +2523,13 @@ static void test_wolfSSL_PKCS12(void)
!defined(NO_ASN) && !defined(NO_PWDBASED) && !defined(NO_RSA)
byte buffer[5300];
char file[] = "./certs/test-servercert.p12";
char pass[] = "a password";
FILE *f;
int bytes, ret;
WOLFSSL_BIO *bio;
WOLFSSL_EVP_PKEY *pkey;
WC_PKCS12 *pkcs12;
WC_PKCS12 *pkcs12_2;
WOLFSSL_X509 *cert;
WOLFSSL_X509 *tmp;
WOLF_STACK_OF(WOLFSSL_X509) *ca;
@@ -2571,6 +2573,7 @@ static void test_wolfSSL_PKCS12(void)
AssertNotNull(cert);
AssertNotNull(ca);
/* should be 2 other certs on stack */
tmp = sk_X509_pop(ca);
AssertNotNull(tmp);
@@ -2580,10 +2583,64 @@ static void test_wolfSSL_PKCS12(void)
X509_free(tmp);
AssertNull(sk_X509_pop(ca));
EVP_PKEY_free(pkey);
X509_free(cert);
sk_X509_free(ca);
/* check PKCS12_create */
AssertNull(PKCS12_create(pass, NULL, NULL, NULL, NULL, -1, -1, -1, -1,0));
AssertIntEQ(PKCS12_parse(pkcs12, "wolfSSL test", &pkey, &cert, &ca),
SSL_SUCCESS);
AssertNotNull((pkcs12_2 = PKCS12_create(pass, NULL, pkey, cert, ca,
-1, -1, 100, -1, 0)));
EVP_PKEY_free(pkey);
X509_free(cert);
sk_X509_free(ca);
AssertIntEQ(PKCS12_parse(pkcs12_2, "a password", &pkey, &cert, &ca),
SSL_SUCCESS);
PKCS12_free(pkcs12_2);
AssertNotNull((pkcs12_2 = PKCS12_create(pass, NULL, pkey, cert, ca,
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2000, 1, 0)));
EVP_PKEY_free(pkey);
X509_free(cert);
sk_X509_free(ca);
AssertIntEQ(PKCS12_parse(pkcs12_2, "a password", &pkey, &cert, &ca),
SSL_SUCCESS);
/* should be 2 other certs on stack */
tmp = sk_X509_pop(ca);
AssertNotNull(tmp);
X509_free(tmp);
tmp = sk_X509_pop(ca);
AssertNotNull(tmp);
X509_free(tmp);
AssertNull(sk_X509_pop(ca));
#ifndef NO_RC4
PKCS12_free(pkcs12_2);
AssertNotNull((pkcs12_2 = PKCS12_create(pass, NULL, pkey, cert, NULL,
NID_pbe_WithSHA1And128BitRC4,
NID_pbe_WithSHA1And128BitRC4,
2000, 1, 0)));
EVP_PKEY_free(pkey);
X509_free(cert);
sk_X509_free(ca);
AssertIntEQ(PKCS12_parse(pkcs12_2, "a password", &pkey, &cert, &ca),
SSL_SUCCESS);
#endif /* NO_RC4 */
EVP_PKEY_free(pkey);
X509_free(cert);
BIO_free(bio);
PKCS12_free(pkcs12);
PKCS12_free(pkcs12_2);
sk_X509_free(ca);
printf(resultFmt, passed);
+458 -63
View File
@@ -842,6 +842,13 @@ static const byte extExtKeyUsageOcspSignOid[] = {43, 6, 1, 5, 5, 7, 3, 9};
/* kdfType */
static const byte pbkdf2Oid[] = {42, 134, 72, 134, 247, 13, 1, 5, 12};
/* PKCS5 */
static const byte pbeSha1Des[] = {42, 134, 72, 134, 247, 13, 1, 5, 10};
/* PKCS12 */
static const byte pbeSha1RC4128[] = {42, 134, 72, 134, 247, 13, 1, 12, 1, 1};
static const byte pbeSha1Des3[] = {42, 134, 72, 134, 247, 13, 1, 12, 1, 3};
static const byte* OidFromId(word32 id, word32 type, word32* oidSz)
{
const byte* oid = NULL;
@@ -1161,6 +1168,25 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz)
}
break;
case oidPBEType:
switch (id) {
case PBE_SHA1_RC4_128:
oid = pbeSha1RC4128;
*oidSz = sizeof(pbeSha1RC4128);
break;
case PBE_SHA1_DES:
oid = pbeSha1Des;
*oidSz = sizeof(pbeSha1Des);
break;
case PBE_SHA1_DES3:
oid = pbeSha1Des3;
*oidSz = sizeof(pbeSha1Des3);
break;
}
break;
case oidKeyWrapType:
switch (id) {
case AES128_WRAP:
@@ -1870,11 +1896,15 @@ static int CheckAlgo(int first, int second, int* id, int* version)
if (first == 1) {
switch (second) {
case 1:
case PBE_SHA1_RC4_128:
*id = PBE_SHA1_RC4_128;
*version = PKCS12v1;
return 0;
case 3:
case PBE_SHA1_DES:
*id = PBE_SHA1_DES;
*version = PKCS12v1;
return 0;
case PBE_SHA1_DES3:
*id = PBE_SHA1_DES3;
*version = PKCS12v1;
return 0;
@@ -1926,10 +1956,10 @@ static int CheckAlgoV2(int oid, int* id)
}
/* Decrypt input in place from parameters based on id */
static int DecryptKey(const char* password, int passwordSz, byte* salt,
/* Decrypt/Encrypt input in place from parameters based on id */
static int CryptKey(const char* password, int passwordSz, byte* salt,
int saltSz, int iterations, int id, byte* input,
int length, int version, byte* cbcIv)
int length, int version, byte* cbcIv, int enc)
{
int typeH;
int derivedLen;
@@ -1942,6 +1972,9 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
(void)input;
(void)length;
(void)enc;
WOLFSSL_ENTER("CryptKey()");
switch (id) {
case PBE_MD5_DES:
@@ -1970,6 +2003,7 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
break;
default:
WOLFSSL_MSG("Unknown/Unsupported encrypt/decrypt id");
return ALGO_ID_E;
}
@@ -2016,6 +2050,7 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
WOLFSSL_MSG("Unknown/Unsupported PKCS version");
return ALGO_ID_E;
}
@@ -2031,13 +2066,18 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
case PBE_MD5_DES:
case PBE_SHA1_DES:
{
Des dec;
Des des;
byte* desIv = key + 8;
if (version == PKCS5v2 || version == PKCS12v1)
desIv = cbcIv;
ret = wc_Des_SetKey(&dec, key, desIv, DES_DECRYPTION);
if (enc) {
ret = wc_Des_SetKey(&des, key, desIv, DES_ENCRYPTION);
}
else {
ret = wc_Des_SetKey(&des, key, desIv, DES_DECRYPTION);
}
if (ret != 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -2045,33 +2085,48 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
return ret;
}
wc_Des_CbcDecrypt(&dec, input, input, length);
if (enc) {
wc_Des_CbcEncrypt(&des, input, input, length);
}
else {
wc_Des_CbcDecrypt(&des, input, input, length);
}
break;
}
case PBE_SHA1_DES3:
{
Des3 dec;
Des3 des;
byte* desIv = key + 24;
if (version == PKCS5v2 || version == PKCS12v1)
desIv = cbcIv;
ret = wc_Des3Init(&dec, NULL, INVALID_DEVID);
ret = wc_Des3Init(&des, NULL, INVALID_DEVID);
if (ret != 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
ret = wc_Des3_SetKey(&dec, key, desIv, DES_DECRYPTION);
if (enc) {
ret = wc_Des3_SetKey(&des, key, desIv, DES_ENCRYPTION);
}
else {
ret = wc_Des3_SetKey(&des, key, desIv, DES_DECRYPTION);
}
if (ret != 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
ret = wc_Des3_CbcDecrypt(&dec, input, input, length);
if (enc) {
ret = wc_Des3_CbcEncrypt(&des, input, input, length);
}
else {
ret = wc_Des3_CbcDecrypt(&des, input, input, length);
}
if (ret != 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
@@ -2113,7 +2168,11 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
#endif
default:
ret = ALGO_ID_E;
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
WOLFSSL_MSG("Unknown/Unsupported encrypt/decryption algorithm");
return ALGO_ID_E;
}
#ifdef WOLFSSL_SMALL_STACK
@@ -2128,64 +2187,45 @@ int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz,
int* algoID, void* heap)
{
word32 tmpIdx = 0;
#ifdef HAVE_ECC
#ifdef HAVE_ECC
ecc_key ecc;
#endif
#ifndef NO_RSA
RsaKey rsa;
#endif
#endif
#ifdef HAVE_ED25519
ed25519_key ed25519;
#endif
if (algoID == NULL) {
return BAD_FUNC_ARG;
}
*algoID = 0;
#ifndef NO_RSA
RsaKey rsa;
#ifndef NO_RSA
if (wc_InitRsaKey(&rsa, heap) == 0) {
if (wc_RsaPrivateKeyDecode(key, &tmpIdx, &rsa, keySz) == 0) {
*algoID = RSAk;
}
else {
WOLFSSL_MSG("Not RSA DER key");
}
wc_FreeRsaKey(&rsa);
wc_InitRsaKey(&rsa, heap);
if (wc_RsaPrivateKeyDecode(key, &tmpIdx, &rsa, keySz) == 0) {
*algoID = RSAk;
}
else {
WOLFSSL_MSG("GetKeyOID wc_InitRsaKey failed");
WOLFSSL_MSG("Not RSA DER key");
}
#endif /* NO_RSA */
#ifdef HAVE_ECC
if (*algoID != RSAk) {
wc_FreeRsaKey(&rsa);
#endif /* NO_RSA */
#ifdef HAVE_ECC
if (algoID == 0) {
tmpIdx = 0;
if (wc_ecc_init_ex(&ecc, heap, INVALID_DEVID) == 0) {
if (wc_EccPrivateKeyDecode(key, &tmpIdx, &ecc, keySz) == 0) {
*algoID = ECDSAk;
wc_ecc_init_ex(&ecc, heap, INVALID_DEVID);
if (wc_EccPrivateKeyDecode(key, &tmpIdx, &ecc, keySz) == 0) {
*algoID = ECDSAk;
/* sanity check on arguments */
if (curveOID == NULL || oidSz == NULL) {
WOLFSSL_MSG("Error getting ECC curve OID");
wc_ecc_free(&ecc);
return BAD_FUNC_ARG;
}
/* 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;
}
/* 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);
}
else {
WOLFSSL_MSG("GetKeyOID wc_ecc_init_ex failed");
WOLFSSL_MSG("Not ECC DER key either");
}
wc_ecc_free(&ecc);
}
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
@@ -2213,13 +2253,218 @@ int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz,
return BAD_FUNC_ARG;
}
(void)curveOID;
(void)oidSz;
return 1;
}
/*
* 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
*/
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;
word32 sz;
word32 seqSz;
word32 inOutIdx = 0;
word32 totalSz = 0;
int version, id;
int ret;
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) < 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;
sz = SetAlgoID(id, out + inOutIdx, oidPBEType, 0);
totalSz += sz; inOutIdx += sz;
if (version == PKCS5v2) {
WOLFSSL_MSG("PKCS5v2 Not supported yet\n");
}
if (salt == NULL || saltSz <= 0) {
saltSz = 8;
salt = saltTmp;
#ifdef WOLFSSL_SMALL_STACK
saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (saltTmp == NULL)
return MEMORY_E;
#endif
if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
WOLFSSL_MSG("Error generating random salt");
#ifdef WOLFSSL_SMALL_STACK
if (saltTmp != NULL)
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
}
/* leave room for a sequence (contains salt and itterations int) */
inOutIdx += MAX_SEQ_SZ; sz = 0;
/* 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 itteration count in buffer */
out[inOutIdx++] = ASN_INTEGER; sz++;
out[inOutIdx++] = sizeof(word32); sz++;
out[inOutIdx++] = (itt >> 24) & 0xFF;
out[inOutIdx++] = (itt >> 16) & 0xFF;
out[inOutIdx++] = (itt >> 8 ) & 0xFF;
out[inOutIdx++] = itt & 0xFF;
sz += 4;
/* 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);
inOutIdx += tmpSz + sz; totalSz += 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) {
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;
return LENGTH_ONLY_E;
}
tmp = XMALLOC(tmpSz, 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;
}
#ifdef WOLFSSL_SMALL_STACK
cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (cbcIv == NULL) {
if (saltTmp != NULL)
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
/* encrypt PKCS#8 wrapped key */
if ((ret = CryptKey(password, passwordSz, salt, saltSz, itt, id,
tmp, tmpSz, version, cbcIv, 1)) < 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 begining */
sz = SetSequence(totalSz, out);
XMEMMOVE(out + sz, out + MAX_SEQ_SZ, totalSz);
return totalSz + sz;
}
/* Remove Encrypted PKCS8 header, move beginning of traditional to beginning
of input */
int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
@@ -2340,8 +2585,8 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
if (ret < 0)
goto exit_tte;
ret = DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length, version, cbcIv);
ret = CryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length, version, cbcIv, 0);
exit_tte:
#ifdef WOLFSSL_SMALL_STACK
@@ -2357,6 +2602,156 @@ exit_tte:
return ret;
}
/* encrypt PKCS 12 content */
int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz,
const char* password, int passwordSz, int vPKCS, int vAlgo,
byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap)
{
word32 sz;
word32 inOutIdx = 0;
word32 tmpIdx = 0;
word32 totalSz = 0;
word32 seqSz;
int ret;
int version, id;
#ifdef WOLFSSL_SMALL_STACK
byte* saltTmp = NULL;
byte* cbcIv = NULL;
#else
byte saltTmp[MAX_SALT_SIZE];
byte cbcIv[MAX_IV_SIZE];
#endif
(void)heap;
WOLFSSL_ENTER("EncryptContent()");
if (CheckAlgo(vPKCS, vAlgo, &id, &version) < 0)
return ASN_INPUT_E; /* Algo ID error */
if (version == PKCS5v2) {
WOLFSSL_MSG("PKCS#5 version 2 not supported yet");
return BAD_FUNC_ARG;
}
if (saltSz > MAX_SALT_SIZE)
return ASN_PARSE_E;
if (out == NULL) {
sz = inputSz;
switch (id) {
case PBE_MD5_DES:
case PBE_SHA1_DES:
case PBE_SHA1_DES3:
/* set to block size of 8 for DES operations. This rounds up
* to the nearset multiple of 8 */
sz &= 0xfffffff8;
sz += 8;
break;
case PBE_SHA1_RC4_128:
break;
case -1:
break;
default:
return ALGO_ID_E;
}
if (saltSz <= 0) {
sz += MAX_SALT_SIZE;
}
else {
sz += saltSz;
}
/* add 2 for tags */
*outSz = sz + MAX_ALGO_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ +
MAX_LENGTH_SZ + MAX_LENGTH_SZ + MAX_SHORT_SZ + 2;
return LENGTH_ONLY_E;
}
if (inOutIdx + MAX_ALGO_SZ + MAX_SEQ_SZ + 1 > *outSz)
return BUFFER_E;
sz = SetAlgoID(id, out + inOutIdx, oidPBEType, 0);
inOutIdx += sz; totalSz += sz;
tmpIdx = inOutIdx;
tmpIdx += MAX_SEQ_SZ; /* save room for salt and itter sequence */
out[tmpIdx++] = ASN_OCTET_STRING;
/* create random salt if one not provided */
if (salt == NULL || saltSz <= 0) {
saltSz = 8;
salt = saltTmp;
#ifdef WOLFSSL_SMALL_STACK
saltTmp = (byte*)XMALLOC(saltSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (saltTmp == NULL)
return MEMORY_E;
#endif
if ((ret = wc_RNG_GenerateBlock(rng, saltTmp, saltSz)) != 0) {
WOLFSSL_MSG("Error generating random salt");
XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
}
if (tmpIdx + MAX_LENGTH_SZ + saltSz + MAX_SHORT_SZ > *outSz)
return BUFFER_E;
sz = SetLength(saltSz, out + tmpIdx);
tmpIdx += sz;
XMEMCPY(out + tmpIdx, salt, saltSz);
tmpIdx += saltSz;
/* place itteration setting in buffer */
out[tmpIdx++] = ASN_INTEGER;
out[tmpIdx++] = sizeof(word32);
out[tmpIdx++] = (itt >> 24) & 0xFF;
out[tmpIdx++] = (itt >> 16) & 0xFF;
out[tmpIdx++] = (itt >> 8) & 0xFF;
out[tmpIdx++] = itt & 0xFF;
/* rewind and place sequence */
sz = tmpIdx - inOutIdx - MAX_SEQ_SZ;
seqSz = SetSequence(sz, out + inOutIdx);
XMEMMOVE(out + inOutIdx + seqSz, out + inOutIdx + MAX_SEQ_SZ, sz);
inOutIdx += seqSz; totalSz += seqSz;
inOutIdx += sz; totalSz += sz;
#ifdef WOLFSSL_SMALL_STACK
cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (cbcIv == NULL) {
XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
#endif
if ((ret = CryptKey(password, passwordSz, salt, saltSz, itt, id,
input, inputSz, version, cbcIv, 1)) < 0) {
return ret; /* encrypt failure */
}
if (inOutIdx + 1 + MAX_LENGTH_SZ + inputSz > *outSz)
return BUFFER_E;
out[inOutIdx++] = ASN_LONG_LENGTH; totalSz++;
sz = SetLength(inputSz, out + inOutIdx);
inOutIdx += sz; totalSz += sz;
XMEMCPY(out + inOutIdx, input, inputSz);
totalSz += inputSz;
return totalSz;
}
/* decrypt PKCS */
int DecryptContent(byte* input, word32 sz,const char* password,int passwordSz)
{
@@ -2477,8 +2872,8 @@ int DecryptContent(byte* input, word32 sz,const char* password,int passwordSz)
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
ret = DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length, version, cbcIv);
ret = CryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length, version, cbcIv, 0);
exit_dc:
+892 -14
View File
@@ -55,8 +55,24 @@ enum {
WC_PKCS12_SafeContentsBag = 672,
WC_PKCS12_DATA = 651,
WC_PKCS12_ENCRYPTED_DATA = 656,
WC_PKCS12_DATA_OBJ_SZ = 11,
};
/* static const byte WC_PKCS12_ENCRYPTED_OID[] =
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06}; */
static const byte WC_PKCS12_DATA_OID[] =
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01};
static const byte WC_PKCS12_CertBag_Type1_OID[] =
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x16, 0x01};
static const byte WC_PKCS12_CertBag_OID[] =
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0c, 0x0a, 0x01, 0x03};
static const byte WC_PKCS12_KeyBag_OID[] =
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0c, 0x0a, 0x01, 0x01};
static const byte WC_PKCS12_ShroudedKeyBag_OID[] =
{0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0c, 0x0a, 0x01, 0x02};
typedef struct ContentInfo {
byte* data;
struct ContentInfo* next;
@@ -454,10 +470,9 @@ exit_gsd:
}
/* check mac on pkcs12, pkcs12->mac has been sanity checked before entering *
* returns the result of comparison, success is 0 */
static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
const byte* psw, word32 pswSz)
/* expects PKCS12 signData to be set up with OID */
static int wc_PKCS12_create_mac(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
const byte* psw, word32 pswSz, byte* out, word32 outSz)
{
Hmac hmac;
MacData* mac;
@@ -465,22 +480,20 @@ static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
int idx = 0;
int id = 3; /* value from RFC 7292 indicating key is used for MAC */
word32 i;
byte digest[MAX_DIGEST_SIZE];
byte unicodePasswd[MAX_UNICODE_SZ];
byte key[MAX_KEY_SIZE];
if (pkcs12 == NULL || pkcs12->signData == NULL || data == NULL ||
out == NULL) {
return BAD_FUNC_ARG;
}
mac = pkcs12->signData;
#ifdef WOLFSSL_DEBUG_PKCS12
printf("Verifying MAC with OID = %d\n", mac->oid);
#endif
/* check if this builds digest size is too small */
if (mac->digestSz > MAX_DIGEST_SIZE) {
WOLFSSL_MSG("PKCS12 max digest size too small");
return BAD_FUNC_ARG;
}
/* unicode set up from asn.c */
if ((pswSz * 2 + 2) > (int)sizeof(unicodePasswd)) {
WOLFSSL_MSG("PKCS12 max unicode size too small");
@@ -526,6 +539,11 @@ static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
return BAD_FUNC_ARG;
}
/* check out buffer is large enough */
if (kLen < 0 || outSz < (word32)kLen) {
return BAD_FUNC_ARG;
}
/* idx contains size of unicodePasswd */
if ((ret = wc_PKCS12_PBKDF_ex(key, unicodePasswd, idx, mac->salt,
mac->saltSz, mac->itt, kLen, typeH, id, pkcs12->heap)) < 0) {
@@ -540,12 +558,46 @@ static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
if (ret == 0)
ret = wc_HmacUpdate(&hmac, data, dataSz);
if (ret == 0)
ret = wc_HmacFinal(&hmac, digest);
ret = wc_HmacFinal(&hmac, out);
wc_HmacFree(&hmac);
if (ret != 0)
return ret;
return kLen; /* same as digest size */
}
/* check mac on pkcs12, pkcs12->mac has been sanity checked before entering *
* returns the result of comparison, success is 0 */
static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
const byte* psw, word32 pswSz)
{
MacData* mac;
int ret;
byte digest[MAX_DIGEST_SIZE];
if (pkcs12 == NULL || pkcs12->signData == NULL || data == NULL) {
return BAD_FUNC_ARG;
}
mac = pkcs12->signData;
#ifdef WOLFSSL_DEBUG_PKCS12
printf("Verifying MAC with OID = %d\n", mac->oid);
#endif
/* check if this builds digest size is too small */
if (mac->digestSz > MAX_DIGEST_SIZE) {
WOLFSSL_MSG("PKCS12 max digest size too small");
return BAD_FUNC_ARG;
}
if ((ret = wc_PKCS12_create_mac(pkcs12, data, dataSz, psw, pswSz,
digest, MAX_DIGEST_SIZE)) < 0) {
return ret;
}
#ifdef WOLFSSL_DEBUG_PKCS12
{
byte* p;
@@ -1071,7 +1123,7 @@ int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
}
else {
/* free list, not wanted */
freeCertList(certList, pkcs12->heap);
wc_FreeCertList(certList, pkcs12->heap);
}
ret = 0; /* success */
@@ -1096,6 +1148,832 @@ exit_pk12par:
}
static int wc_PKCS12_shroud_key(WC_PKCS12* pkcs12, WC_RNG* rng,
byte* out, word32* outSz, byte* key, word32 keySz, int vAlgo,
const char* pass, int passSz, int itt)
{
void* heap;
word32 tmpIdx = 0;
int vPKCS = 1; /* PKCS#12 is always set to 1 */
word32 sz;
word32 totalSz = 0;
int ret;
if (outSz == NULL || pkcs12 == NULL || rng == NULL || key == NULL ||
pass == NULL) {
return BAD_FUNC_ARG;
}
heap = wc_PKCS12_GetHeap(pkcs12);
/* check if trying to get size */
if (out != NULL) {
tmpIdx += MAX_LENGTH_SZ + 1; /* save room for length and tag (+1) */
sz = *outSz - tmpIdx;
}
/* case of no encryption */
if (vAlgo < 0) {
const byte* curveOID = NULL;
word32 oidSz = 0;
int algoID;
WOLFSSL_MSG("creating PKCS12 Key Bag");
/* check key type and get OID if ECC */
if ((ret = wc_GetKeyOID(key, keySz, &curveOID, &oidSz, &algoID, heap))
< 0) {
return ret;
}
/* PKCS#8 wrapping around key */
ret = wc_CreatePKCS8Key(out + tmpIdx, &sz, key, keySz, algoID,
curveOID, oidSz);
}
else {
WOLFSSL_MSG("creating PKCS12 Shrouded Key Bag");
ret = UnTraditionalEnc(key, keySz, out + tmpIdx, &sz, pass, passSz,
vPKCS, vAlgo, NULL, 0, itt, rng, heap);
}
if (ret == LENGTH_ONLY_E) {
*outSz = sz + MAX_LENGTH_SZ + 1;
return LENGTH_ONLY_E;
}
if (ret < 0) {
return ret;
}
totalSz += ret;
/* out should not be null at this point but check before writing */
if (out == NULL) {
return BAD_FUNC_ARG;
}
/* rewind index and set tag and length */
tmpIdx -= MAX_LENGTH_SZ + 1;
sz = SetExplicit(0, ret, out + tmpIdx);
tmpIdx += sz; totalSz += sz;
XMEMMOVE(out + tmpIdx, out + MAX_LENGTH_SZ + 1, ret);
return totalSz;
}
static int wc_PKCS12_create_key_bag(WC_PKCS12* pkcs12, WC_RNG* rng,
byte* out, word32* outSz, byte* key, word32 keySz, int algo, int iter,
char* pass, int passSz)
{
void* heap;
byte* tmp;
word32 length = 0;
word32 idx = 0;
word32 totalSz = 0;
word32 sz;
word32 i;
word32 tmpSz;
int ret;
/* get max size for shrouded key */
ret = wc_PKCS12_shroud_key(pkcs12, rng, NULL, &length, key, keySz,
algo, pass, passSz, iter);
if (ret != LENGTH_ONLY_E && ret < 0) {
return ret;
}
if (out == NULL) {
*outSz = MAX_SEQ_SZ + WC_PKCS12_DATA_OBJ_SZ + 1 + MAX_LENGTH_SZ +
length;
return LENGTH_ONLY_E;
}
heap = wc_PKCS12_GetHeap(pkcs12);
/* leave room for sequence */
idx += MAX_SEQ_SZ;
if (algo < 0) { /* not encrypted */
out[idx++] = ASN_OBJECT_ID; totalSz++;
sz = SetLength(sizeof(WC_PKCS12_KeyBag_OID), out + idx);
idx += sz; totalSz += sz;
for (i = 0; i < sizeof(WC_PKCS12_KeyBag_OID); i++) {
out[idx++] = WC_PKCS12_KeyBag_OID[i]; totalSz++;
}
}
else { /* encrypted */
out[idx++] = ASN_OBJECT_ID; totalSz++;
sz = SetLength(sizeof(WC_PKCS12_ShroudedKeyBag_OID), out + idx);
idx += sz; totalSz += sz;
for (i = 0; i < sizeof(WC_PKCS12_ShroudedKeyBag_OID); i++) {
out[idx++] = WC_PKCS12_ShroudedKeyBag_OID[i]; totalSz++;
}
}
/* shroud key */
tmp = (byte*)XMALLOC(length, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (tmp == NULL) {
return MEMORY_E;
}
ret = wc_PKCS12_shroud_key(pkcs12, rng, tmp, &length, key, keySz,
algo, pass, passSz, iter);
if (ret < 0) {
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
length = ret;
XMEMCPY(out + idx, tmp, length);
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
totalSz += length;
/* set begining sequence */
tmpSz = SetSequence(totalSz, out);
XMEMMOVE(out + tmpSz, out + MAX_SEQ_SZ, totalSz);
return totalSz + tmpSz;
}
static int wc_PKCS12_create_cert_bag(WC_PKCS12* pkcs12,
byte* out, word32* outSz, byte* cert, word32 certSz)
{
word32 length = 0;
word32 idx = 0;
word32 totalSz = 0;
word32 sz;
int WC_CERTBAG_OBJECT_ID = 13;
int WC_CERTBAG1_OBJECT_ID = 12;
word32 i;
word32 tmpSz;
if (out == NULL) {
*outSz = MAX_SEQ_SZ + WC_CERTBAG_OBJECT_ID + 1 + MAX_LENGTH_SZ +
MAX_SEQ_SZ + WC_CERTBAG1_OBJECT_ID + 1 + MAX_LENGTH_SZ + 1 +
MAX_LENGTH_SZ + certSz;
return LENGTH_ONLY_E;
}
/* check buffer size able to handle max size */
if (*outSz < (MAX_SEQ_SZ + WC_CERTBAG_OBJECT_ID + 1 + MAX_LENGTH_SZ +
MAX_SEQ_SZ + WC_CERTBAG1_OBJECT_ID + 1 + MAX_LENGTH_SZ + 1 +
MAX_LENGTH_SZ + certSz)) {
return BUFFER_E;
}
/* save room for sequence */
idx += MAX_SEQ_SZ;
/* objectId WC_PKCS12_CertBag */
out[idx++] = ASN_OBJECT_ID; totalSz++;
sz = SetLength(sizeof(WC_PKCS12_CertBag_OID), out + idx);
idx += sz; totalSz += sz;
for (i = 0; i < sizeof(WC_PKCS12_CertBag_OID); i++) {
out[idx++] = WC_PKCS12_CertBag_OID[i]; totalSz++;
}
/**** Cert Bag type 1 ****/
out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC); totalSz++;
/* save room for length and sequence */
idx += MAX_LENGTH_SZ;
idx += MAX_SEQ_SZ;
/* object id WC_PKCS12_CertBag_Type1 */
out[idx++] = ASN_OBJECT_ID; length++;
sz = SetLength(sizeof(WC_PKCS12_CertBag_Type1_OID), out + idx);
idx += sz; length += sz;
for (i = 0; i < sizeof(WC_PKCS12_CertBag_Type1_OID); i++) {
out[idx++] = WC_PKCS12_CertBag_Type1_OID[i]; length++;
}
out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC); length++;
sz = 0;
idx += MAX_LENGTH_SZ; /* save room for length */
/* place the cert in the buffer */
out[idx++] = ASN_OCTET_STRING; sz++;
tmpSz = SetLength(certSz, out + idx);
idx += tmpSz; sz += tmpSz;
XMEMCPY(out + idx, cert, certSz);
idx += certSz; sz += certSz;
/* rewind idx and place length */
idx -= (sz + MAX_LENGTH_SZ);
tmpSz = SetLength(sz, out + idx);
XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, sz);
idx += tmpSz + sz; length += tmpSz + sz;
/* rewind idx and set sequence */
idx -= (length + MAX_SEQ_SZ);
tmpSz = SetSequence(length, out + idx);
XMEMMOVE(out + idx + tmpSz, out + idx + MAX_SEQ_SZ, length);
length += tmpSz;
/* place final length */
idx -= MAX_LENGTH_SZ;
tmpSz = SetLength(length, out + idx);
XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, length);
length += tmpSz;
/* place final sequence */
totalSz += length;
tmpSz = SetSequence(totalSz, out);
XMEMMOVE(out + tmpSz, out + MAX_SEQ_SZ, totalSz);
(void)pkcs12;
return totalSz + tmpSz;
}
static int wc_PKCS12_encrypt_content(WC_PKCS12* pkcs12, WC_RNG* rng,
byte* out, word32* outSz, byte* content, word32 contentSz, int vAlgo,
const char* pass, int passSz, int iter, int type)
{
void* heap;
int vPKCS = 1; /* PKCS#12 is always set to 1 */
int ret;
byte* tmp;
word32 idx = 0;
word32 totalSz = 0;
word32 length = 0;
word32 tmpSz;
word32 encSz;
word32 i;
WOLFSSL_MSG("encrypting PKCS12 content");
heap = wc_PKCS12_GetHeap(pkcs12);
/* ENCRYPTED DATA
* ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC
* length
* sequence
* short int
* sequence
* get object id */
if (type == WC_PKCS12_ENCRYPTED_DATA) {
if (out == NULL) {
*outSz = 1 + MAX_LENGTH_SZ + MAX_SEQ_SZ + MAX_VERSION_SZ +
MAX_SEQ_SZ + WC_PKCS12_DATA_OBJ_SZ;
ret = EncryptContent(NULL, contentSz + MAX_SEQ_SZ, NULL, &encSz,
pass, passSz, vPKCS, vAlgo, NULL, 0, iter, rng, heap);
if (ret != LENGTH_ONLY_E) {
return ret;
}
*outSz += encSz;
return LENGTH_ONLY_E;
}
if (*outSz < (1 + MAX_LENGTH_SZ + MAX_SEQ_SZ + MAX_VERSION_SZ)) {
return BUFFER_E;
}
out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC); totalSz++;
/* save room for length and sequence */
idx += MAX_LENGTH_SZ;
idx += MAX_SEQ_SZ;
tmpSz = SetMyVersion(0, out + idx, 0);
idx += tmpSz; length += tmpSz;
encSz = contentSz;
if ((ret = EncryptContent(NULL, contentSz, NULL, &encSz,
pass, passSz, vPKCS, vAlgo, NULL, 0, iter, rng, heap)) < 0) {
if (ret != LENGTH_ONLY_E) {
return ret;
}
}
if (*outSz < (idx + MAX_SEQ_SZ + WC_PKCS12_DATA_OBJ_SZ + encSz)) {
return BUFFER_E;
}
tmp = (byte*)XMALLOC(encSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (tmp == NULL) {
return MEMORY_E;
}
if ((ret = EncryptContent(content, contentSz, tmp, &encSz,
pass, passSz, vPKCS, vAlgo, NULL, 0, iter, rng, heap)) < 0) {
return ret;
}
encSz = ret;
#ifdef WOLFSSL_DEBUG_PKCS12
{
byte* p;
for (printf("(size %u) Encrypted Content = ", encSz),
p = (byte*)tmp;
p < (byte*)tmp + encSz;
printf("%02X", *p), p++);
printf("\n");
}
#endif
tmpSz = SetSequence(WC_PKCS12_DATA_OBJ_SZ + encSz, out + idx);
idx += tmpSz; length += tmpSz;
out[idx++] = ASN_OBJECT_ID; length++;
tmpSz = SetLength(sizeof(WC_PKCS12_DATA_OID), out + idx);
idx += tmpSz; length += tmpSz;
for (i = 0; i < sizeof(WC_PKCS12_DATA_OID); i++) {
out[idx++] = WC_PKCS12_DATA_OID[i]; length++;
}
/* copy over encrypted data */
XMEMCPY(out + idx, tmp, encSz);
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
idx += encSz; length += encSz;
/* rewind and place sequence */
idx -= (length + MAX_SEQ_SZ);
tmpSz = SetSequence(length, out + idx);
XMEMMOVE(out + idx + tmpSz, out + idx + MAX_SEQ_SZ, length);
length += tmpSz;
/* now place length */
idx -= MAX_LENGTH_SZ;
tmpSz = SetLength(length, out + idx);
XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, length);
totalSz += length + tmpSz;
return totalSz;
}
/* DATA
* ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC
* length
* ASN_OCTET_STRING
* length
* sequence containing all bags */
if (type == WC_PKCS12_DATA) {
if (out == NULL) {
*outSz = 1 + MAX_LENGTH_SZ + 1 + MAX_LENGTH_SZ + contentSz;
return LENGTH_ONLY_E;
}
if (*outSz < (1 + MAX_LENGTH_SZ + 1 + MAX_LENGTH_SZ + contentSz)) {
return BUFFER_E;
}
out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC);
totalSz++;
/* save room for length */
idx += MAX_LENGTH_SZ;
out[idx++] = ASN_OCTET_STRING; length++;
tmpSz = SetLength(contentSz, out + idx);
idx += tmpSz; length += tmpSz;
/* sequence containing all bags */
XMEMCPY(out + idx, content, contentSz);
idx += contentSz; length += contentSz;
idx -= (MAX_LENGTH_SZ + length);
tmpSz = SetLength(length, out + idx);
XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, length);
totalSz += length + tmpSz;
return totalSz;
}
WOLFSSL_MSG("Unknown/Unsupported content type");
return BAD_FUNC_ARG;
}
/*
* p : password to use with encryption
* name : friendlyName to use
* key : DER format of key with keySz being the size of this buffer
* cert : DER format of certificate with certSz being the size of this buffer
* ca : a list of extra certificates
* nidKey : type of encryption to use on the key (-1 means no encryption)
* nidCert : type of ecnryption to use on the certificate
* (-1 means no encryption)
* iter : number of itterations with encryption
* macIter : number of itterations when creating MAC
* keyType : flag for signature and/or encryption key
*/
WC_PKCS12* wc_PKCS12_create(char* pass, word32 passSz, char* name,
byte* key, word32 keySz, byte* cert, word32 certSz, WC_DerCertList* ca,
int nidKey, int nidCert, int iter, int macIter, int keyType, void* heap)
{
WC_PKCS12* pkcs12;
AuthenticatedSafe* safe;
ContentInfo* ci;
WC_RNG rng;
int algo;
int ret;
int type;
word32 idx;
word32 sz;
word32 tmpSz;
byte* certCi = NULL;
word32 certCiSz;
byte* keyCi;
word32 keyCiSz;
byte* certBuf = NULL;
word32 certBufSz;
byte* keyBuf;
word32 keyBufSz;
WOLFSSL_ENTER("wc_PKCS12_create()");
pkcs12 = wc_PKCS12_new();
wc_PKCS12_SetHeap(pkcs12, heap);
wc_InitRng_ex(&rng, heap, INVALID_DEVID);
if (iter <= 0) {
iter = WC_PKCS12_ITT_DEFAULT;
}
/**** add private key bag ****/
switch (nidKey) {
case PBE_SHA1_RC4_128:
algo = 1;
break;
case PBE_SHA1_DES:
algo = 2;
break;
case PBE_SHA1_DES3:
algo = 3;
break;
/* no encryption */
case -1:
algo = -1;
break;
default:
WOLFSSL_MSG("Unknown/Unsupported key encryption");
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
/* get max size for key bag */
ret = wc_PKCS12_create_key_bag(pkcs12, &rng, NULL, &keyBufSz, key, keySz,
algo, iter, pass, passSz);
if (ret != LENGTH_ONLY_E && ret < 0) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
WOLFSSL_LEAVE("wc_PKCS12_create", ret);
return NULL;
}
/* account for sequence around bag */
keyBufSz += MAX_SEQ_SZ;
keyBuf = (byte*)XMALLOC(keyBufSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (keyBuf == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
WOLFSSL_MSG("Memory error");
return NULL;
}
ret = wc_PKCS12_create_key_bag(pkcs12, &rng, keyBuf + MAX_SEQ_SZ, &keyBufSz,
key, keySz, algo, iter, pass, passSz);
if (ret < 0) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_LEAVE("wc_PKCS12_create", ret);
return NULL;
}
keyBufSz = ret;
tmpSz = SetSequence(keyBufSz, keyBuf);
XMEMMOVE(keyBuf + tmpSz, keyBuf + MAX_SEQ_SZ, keyBufSz);
keyBufSz += tmpSz;
ret = wc_PKCS12_encrypt_content(pkcs12, &rng, NULL, &keyCiSz,
NULL, keyBufSz, algo, pass, passSz, iter, WC_PKCS12_DATA);
if (ret != LENGTH_ONLY_E) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_LEAVE("wc_PKCS12_create", ret);
return NULL;
}
keyCi = (byte*)XMALLOC(keyCiSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (keyCi == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
return NULL;
}
ret = wc_PKCS12_encrypt_content(pkcs12, &rng, keyCi, &keyCiSz,
keyBuf, keyBufSz, algo, pass, passSz, iter, WC_PKCS12_DATA);
if (ret < 0 ) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
WOLFSSL_LEAVE("wc_PKCS12_create", ret);
return NULL;
}
keyCiSz = ret;
XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_DEBUG_PKCS12
{
byte* p;
for (printf("(size %u) Key Content Info = ", keyCiSz), p = (byte*)keyCi;
p < (byte*)keyCi + keyCiSz;
printf("%02X", *p), p++);
printf("\n");
}
#endif
/**** add main certificate bag and extras ****/
switch (nidCert) {
case PBE_SHA1_RC4_128:
type = WC_PKCS12_ENCRYPTED_DATA;
algo = 1;
break;
case PBE_SHA1_DES:
type = WC_PKCS12_ENCRYPTED_DATA;
algo = 2;
break;
case PBE_SHA1_DES3:
type = WC_PKCS12_ENCRYPTED_DATA;
algo = 3;
break;
case -1:
type = WC_PKCS12_DATA;
algo = -1;
break;
default:
WOLFSSL_MSG("Unknown/Unsupported certificate encryption");
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
/* get max size of buffer needed */
ret = wc_PKCS12_create_cert_bag(pkcs12, NULL, &certBufSz, cert, certSz);
if (ret != LENGTH_ONLY_E) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
if (ca != NULL) {
WC_DerCertList* current = ca;
word32 curBufSz = 0;
/* get max buffer size */
while (current != NULL) {
ret = wc_PKCS12_create_cert_bag(pkcs12, NULL, &curBufSz,
current->buffer, current->bufferSz);
if (ret != LENGTH_ONLY_E) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
certBufSz += curBufSz;
current = current->next;
}
}
/* account for Sequence that holds all certificate bags */
certBufSz += MAX_SEQ_SZ;
/* completed getting max size, now create buffer and start adding bags */
certBuf = (byte*)XMALLOC(certBufSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (certBuf == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
WOLFSSL_MSG("Memory error creating certificate bags");
return NULL;
}
idx = 0;
idx += MAX_SEQ_SZ;
sz = certBufSz - idx;
if ((ret = wc_PKCS12_create_cert_bag(pkcs12, certBuf + idx, &sz,
cert, certSz)) < 0) {
XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
idx += ret;
if (ca != NULL) {
WC_DerCertList* current = ca;
while (current != NULL) {
sz = certBufSz - idx;
if ((ret = wc_PKCS12_create_cert_bag(pkcs12, certBuf + idx, &sz,
current->buffer, current->bufferSz)) < 0) {
XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
idx += ret;
current = current->next;
}
}
/* set sequence and create encrypted content with all certificate bags */
tmpSz = SetSequence(idx - MAX_SEQ_SZ, certBuf);
XMEMMOVE(certBuf + tmpSz, certBuf + MAX_SEQ_SZ, idx - MAX_SEQ_SZ);
certBufSz = tmpSz + (idx - MAX_SEQ_SZ);
/* get buffer size needed for content info */
ret = wc_PKCS12_encrypt_content(pkcs12, &rng, NULL, &certCiSz,
NULL, certBufSz, algo, pass, passSz, iter, type);
if (ret != LENGTH_ONLY_E) {
XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
WOLFSSL_LEAVE("wc_PKCS12_create()", ret);
return NULL;
}
certCi = (byte*)XMALLOC(certCiSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
if (certCi == NULL) {
XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
ret = wc_PKCS12_encrypt_content(pkcs12, &rng, certCi, &certCiSz,
certBuf, certBufSz, algo, pass, passSz, iter, type);
if (ret < 0) {
XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
WOLFSSL_LEAVE("wc_PKCS12_create()", ret);
return NULL;
}
certCiSz = ret;
XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_DEBUG_PKCS12
{
byte* p;
for (printf("(size %u) Encrypted Certificate Content Info = ",certCiSz),
p = (byte*)certCi;
p < (byte*)certCi + certCiSz;
printf("%02X", *p), p++);
printf("\n");
}
#endif
/**** create safe and and Content Info ****/
safe = (AuthenticatedSafe*)XMALLOC(sizeof(AuthenticatedSafe), heap,
DYNAMIC_TYPE_PKCS);
if (safe == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
pkcs12->safe = safe; /* set so all of safe is free'd with wc_PKCS12_free */
XMEMSET(safe, 0, sizeof(AuthenticatedSafe));
safe->dataSz = certCiSz + keyCiSz;
safe->data = (byte*)XMALLOC(safe->dataSz, heap, DYNAMIC_TYPE_PKCS);
if (safe->data == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
XMEMCPY(safe->data, certCi, certCiSz);
XMEMCPY(safe->data + certCiSz, keyCi, keyCiSz);
XFREE(certCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
safe->numCI = 2;
/* add Content Info structs to safe, key first then cert */
ci = (ContentInfo*)XMALLOC(sizeof(ContentInfo), heap, DYNAMIC_TYPE_PKCS);
if (ci == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
XMEMSET(ci, 0, sizeof(ContentInfo));
safe->CI = ci;
ci->data = safe->data + certCiSz;
ci->dataSz = keyCiSz;
ci->type = WC_PKCS12_DATA;
ci = (ContentInfo*)XMALLOC(sizeof(ContentInfo), heap, DYNAMIC_TYPE_PKCS);
if (ci == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
XMEMSET(ci, 0, sizeof(ContentInfo));
ci->next = safe->CI;
safe->CI = ci;
ci->data = safe->data;
ci->dataSz = certCiSz;
if (nidCert < 0) {
ci->type = WC_PKCS12_DATA;
}
else {
ci->type = WC_PKCS12_ENCRYPTED_DATA;
}
/* create MAC */
if (macIter > 0) {
MacData* mac;
byte digest[MAX_DIGEST_SIZE]; /* for MAC */
mac = (MacData*)XMALLOC(sizeof(MacData), heap, DYNAMIC_TYPE_PKCS);
if (mac == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
pkcs12->signData = mac; /* now wc_PKCS12_free will free all mac too */
#ifndef NO_SHA256
mac->oid = SHA256h;
#elif !defined(NO_SHA)
mac->oid = SHA;
#elif defined(WOLFSSL_SHA384)
mac->oid = SHA384;
#elif defined(WOLFSSL_SHA512)
mac->oid = SHA512;
#elif
WOLFSSL_MSG("No supported hash algorithm compiled in!");
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
#endif
/* if macIter is 0 then default to 1 */
if (macIter == 0) {
mac->itt = WC_PKCS12_MAC_DEFAULT;
}
else {
mac->itt = macIter;
}
/* set mac salt */
mac->saltSz = 8;
mac->salt = (byte*)XMALLOC(mac->saltSz, heap, DYNAMIC_TYPE_PKCS);
if (mac->salt == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
if ((ret = wc_RNG_GenerateBlock(&rng, mac->salt, mac->saltSz)) != 0) {
WOLFSSL_MSG("Error generating random salt");
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
ret = wc_PKCS12_create_mac(pkcs12, safe->data, safe->dataSz,
(const byte*)pass, passSz, digest, MAX_DIGEST_SIZE);
if (ret < 0) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
mac->digestSz = ret;
mac->digest = (byte*)XMALLOC(ret, heap, DYNAMIC_TYPE_PKCS);
if (mac->digest == NULL) {
wc_PKCS12_free(pkcs12);
wc_FreeRng(&rng);
return NULL;
}
XMEMCPY(mac->digest, digest, mac->digestSz);
}
wc_FreeRng(&rng);
(void)name;
(void)keyType;
return pkcs12;
}
/* if using a specific memory heap */
int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap)
{
@@ -1104,7 +1982,7 @@ int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap)
}
pkcs12->heap = heap;
return 0;
return 1;
}
+14
View File
@@ -21,8 +21,19 @@
/* pkcs12.h for openssl */
#include <wolfssl/openssl/ssl.h>
#include <wolfssl/wolfcrypt/pkcs12.h>
#ifndef WOLFSSL_PKCS12_COMPAT_H_
#define WOLFSSL_PKCS12_COMPAT_H_
#define NID_pbe_WithSHA1AndDES_CBC 2
#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 3
#define NID_pbe_WithSHA1And128BitRC4 1
#define PKCS12_DEFAULT_ITER WC_PKCS12_ITT_DEFAULT
/* wolfCrypt level does not make use of ssl.h */
#define PKCS12 WC_PKCS12
#define PKCS12_new wc_PKCS12_new
@@ -31,5 +42,8 @@
/* wolfSSL level using structs from ssl.h and calls down to wolfCrypt */
#define d2i_PKCS12_bio wolfSSL_d2i_PKCS12_bio
#define PKCS12_parse wolfSSL_PKCS12_parse
#define PKCS12_create wolfSSL_PKCS12_create
#define PKCS12_PBE_add wolfSSL_PKCS12_PBE_add
#endif /* WOLFSSL_PKCS12_COMPAT_H_ */
+6 -1
View File
@@ -1415,7 +1415,12 @@ typedef struct WC_PKCS12 WC_PKCS12;
WOLFSSL_API WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio,
WC_PKCS12** pkcs12);
WOLFSSL_API int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, WOLF_STACK_OF(WOLFSSL_X509)** ca);
WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert,
WOLF_STACK_OF(WOLFSSL_X509)** ca);
WOLFSSL_API WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name,
WOLFSSL_EVP_PKEY* pkey, WOLFSSL_X509* cert,
WOLF_STACK_OF(WOLFSSL_X509)* ca,
int keyNID, int certNID, int itt, int macItt, int keytype);
WOLFSSL_API void wolfSSL_PKCS12_PBE_add(void);
+15 -4
View File
@@ -108,10 +108,13 @@ enum DN_Tags {
enum PBES {
PBE_MD5_DES = 0,
PBE_SHA1_DES = 1,
PBE_SHA1_DES3 = 2,
PBE_SHA1_RC4_128 = 3,
PBE_SHA1_RC4_128 = 1,
PBE_SHA1_DES = 2,
PBE_SHA1_DES3 = 3,
PBE_AES256_CBC = 4,
PBE_SHA1_RC4_128_SUM = 657,
PBE_SHA1_DES3_SUM = 659,
PBES2 = 13 /* algo ID */
};
@@ -146,6 +149,7 @@ enum Misc_ASN {
MAX_ENCODED_SIG_SZ = 512,
MAX_SIG_SZ = 256,
MAX_ALGO_SZ = 20,
MAX_SHORT_SZ = 6, /* asn int + byte len + 4 byte length */
MAX_SEQ_SZ = 5, /* enum(seq | con) + length(4) */
MAX_SET_SZ = 5, /* enum(set | con) + length(4) */
MAX_OCTET_STR_SZ = 5, /* enum(set | con) + length(4) */
@@ -214,7 +218,8 @@ enum Oid_Types {
oidKdfType = 11,
oidKeyWrapType = 12,
oidCmsKeyAgreeType = 13,
oidHmacType = 14,
oidPBEType = 14,
oidHmacType = 15,
oidIgnoreType
};
@@ -763,7 +768,13 @@ WOLFSSL_ASN_API int ToTraditional(byte* buffer, word32 length);
WOLFSSL_LOCAL int ToTraditionalInline(const byte* input, word32* inOutIdx,
word32 length);
WOLFSSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*,int);
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);
WOLFSSL_LOCAL int DecryptContent(byte* input, word32 sz,const char* psw,int pswSz);
WOLFSSL_LOCAL int EncryptContent(byte* input, word32 sz, byte* out, word32* outSz,
const char* password,int passwordSz, int vPKCS, int vAlgo,
byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap);
WOLFSSL_LOCAL int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID,
word32* oidSz, int* algoID, void* heap);
+13 -3
View File
@@ -39,7 +39,11 @@ typedef struct WC_DerCertList { /* dereferenced in ssl.c */
struct WC_DerCertList* next;
} WC_DerCertList;
/* default values for creating PKCS12 */
enum {
WC_PKCS12_ITT_DEFAULT = 2048,
WC_PKCS12_MAC_DEFAULT = 1,
};
WOLFSSL_API WC_PKCS12* wc_PKCS12_new(void);
WOLFSSL_API void wc_PKCS12_free(WC_PKCS12* pkcs12);
@@ -47,10 +51,16 @@ WOLFSSL_API int wc_d2i_PKCS12(const byte* der, word32 derSz, WC_PKCS12* pkcs12);
WOLFSSL_API int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
byte** pkey, word32* pkeySz, byte** cert, word32* certSz,
WC_DerCertList** ca);
WOLFSSL_API WC_PKCS12* wc_PKCS12_create(char* pass, word32 passSz,
char* name, byte* key, word32 keySz, byte* cert, word32 certSz,
WC_DerCertList* ca, int nidKey, int nidCert, int iter, int macIter,
int keyType, void* heap);
WOLFSSL_LOCAL int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap);
WOLFSSL_LOCAL void* wc_PKCS12_GetHeap(WC_PKCS12* pkcs12);
WOLFSSL_API int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap);
WOLFSSL_API void* wc_PKCS12_GetHeap(WC_PKCS12* pkcs12);
WOLFSSL_LOCAL void wc_FreeCertList(WC_DerCertList* list, void* heap);
#ifdef __cplusplus
} /* extern "C" */