mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-10 10:50:50 +02:00
PKCS12 create function
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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" */
|
||||
|
||||
Reference in New Issue
Block a user