int rsa_test() { byte tmp[1024], tmp2[2048]; size_t bytes, bytes2; RsaKey key; RNG rng; word32 idx = 0; int ret; byte in[] = "Everyone gets Friday off."; word32 inLen = (word32)strlen((char*)in); byte out[64]; byte plain[64]; DecodedCert cert; FILE* file = fopen(clientKey, "rb"), * file2; if (!file) return -40; bytes = fread(tmp, 1, 1024, file); InitRsaKey(&key, 0); ret = RsaPrivateKeyDecode(tmp, &idx, &key, (word32)bytes); if (ret != 0) return -41; ret = InitRng(&rng); if (ret != 0) return -42; ret = RsaPublicEncrypt(in, inLen, out, sizeof(out), &key, &rng); ret = RsaPrivateDecrypt(out, 64, plain, sizeof(plain), &key); if (memcmp(plain, in, inLen)) return -45; ret = RsaSSL_Sign(in, inLen, out, sizeof(out), &key, &rng); memset(plain, 0, sizeof(plain)); ret = RsaSSL_Verify(out, 64, plain, sizeof(plain), &key); if (memcmp(plain, in, ret)) return -46; file2 = fopen(clientCert, "rb"); if (!file2) return -47; bytes2 = fread(tmp2, 1, 2048, file2); InitDecodedCert(&cert, (byte*)&tmp2, 0); ret = ParseCert(&cert, (word32)bytes2, CERT_TYPE, NO_VERIFY, 0); if (ret != 0) return -48; FreeDecodedCert(&cert); FreeRsaKey(&key); fclose(file2); fclose(file); return 0; }
void bench_rsa(void) { int i; byte tmp[3072]; size_t bytes; word32 idx = 0; byte message[] = "Everyone gets Friday off."; byte enc[512]; /* for up to 4096 bit */ byte* output; const int len = (int)strlen((char*)message); double start, total, each, milliEach; RsaKey rsaKey; FILE* file = fopen("./certs/rsa2048.der", "rb"); if (!file) { printf("can't find ./certs/rsa2048.der, " "Please run from CyaSSL home dir\n"); return; } InitRng(&rng); bytes = fread(tmp, 1, sizeof(tmp), file); InitRsaKey(&rsaKey, 0); bytes = RsaPrivateKeyDecode(tmp, &idx, &rsaKey, (word32)bytes); start = current_time(); for (i = 0; i < times; i++) bytes = RsaPublicEncrypt(message,len,enc,sizeof(enc), &rsaKey, &rng); total = current_time() - start; each = total / times; /* per second */ milliEach = each * 1000; /* milliseconds */ printf("RSA 2048 encryption took %6.2f milliseconds, avg over %d" " iterations\n", milliEach, times); start = current_time(); for (i = 0; i < times; i++) RsaPrivateDecryptInline(enc, (word32)bytes, &output, &rsaKey); total = current_time() - start; each = total / times; /* per second */ milliEach = each * 1000; /* milliseconds */ printf("RSA 2048 decryption took %6.2f milliseconds, avg over %d" " iterations\n", milliEach, times); fclose(file); FreeRsaKey(&rsaKey); }
/* RSA Initialize */ int CRYPT_RSA_Initialize(CRYPT_RSA_CTX* rsa) { if (rsa == NULL) return BAD_FUNC_ARG; rsa->holder = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); if (rsa->holder == NULL) return -1; return InitRsaKey((RsaKey*)rsa->holder, NULL); }
void bench_rsa() { int i; byte tmp[1024]; size_t bytes; word32 idx = 0; byte message[] = "Everyone gets Friday off."; byte cipher[128]; /* for 1024 bit */ byte plain[128]; /* for 1024 bit */ const int len = (int)strlen((char*)message); double start, total, each, milliEach; RsaKey key; FILE* file = fopen("./rsa1024.der", "rb"); if (!file) { printf("can't find ./rsa1024.der\n"); return; } bytes = fread(tmp, 1, 1024, file); InitRsaKey(&key, 0); bytes = RsaPrivateKeyDecode(tmp, &idx, &key, (word32)bytes); start = current_time(); for (i = 0; i < times; i++) RsaPublicEncrypt(message, len, cipher, sizeof(cipher), &key, &rng); total = current_time() - start; each = total / times; /* per second */ milliEach = each * 1000; /* milliseconds */ printf("RSA 1024 encryption took %6.2f milliseconds, avg over %d" " iterations\n", milliEach, times); start = current_time(); for (i = 0; i < times; i++) RsaPrivateDecrypt(cipher, 128, plain, sizeof(plain), &key); total = current_time() - start; each = total / times; /* per second */ milliEach = each * 1000; /* milliseconds */ printf("RSA 1024 decryption took %6.2f milliseconds, avg over %d" " iterations\n", milliEach, times); fclose(file); FreeRsaKey(&key); }
void bench_rsaKeyGen(void) { RsaKey genKey; double start, total, each, milliEach; int i; const int genTimes = 5; /* 1024 bit */ start = current_time(1); for(i = 0; i < genTimes; i++) { InitRsaKey(&genKey, 0); MakeRsaKey(&genKey, 1024, 65537, &rng); FreeRsaKey(&genKey); } total = current_time(0) - start; each = total / genTimes; /* per second */ milliEach = each * 1000; /* millisconds */ printf("\n"); printf("RSA 1024 key generation %6.2f milliseconds, avg over %d" " iterations\n", milliEach, genTimes); /* 2048 bit */ start = current_time(1); for(i = 0; i < genTimes; i++) { InitRsaKey(&genKey, 0); MakeRsaKey(&genKey, 2048, 65537, &rng); FreeRsaKey(&genKey); } total = current_time(0) - start; each = total / genTimes; /* per second */ milliEach = each * 1000; /* millisconds */ printf("RSA 2048 key generation %6.2f milliseconds, avg over %d" " iterations\n", milliEach, genTimes); }
/* check mcapi rsa */ static int check_rsa(void) { CRYPT_RSA_CTX mcRsa; RsaKey defRsa; int ret; int ret2; unsigned int keySz = (unsigned int)sizeof(client_key_der_1024); unsigned int idx = 0; byte out1[256]; byte out2[256]; InitRsaKey(&defRsa, NULL); ret = CRYPT_RSA_Initialize(&mcRsa); if (ret != 0) { printf("mcapi rsa init failed\n"); return -1; } ret = CRYPT_RSA_PrivateKeyDecode(&mcRsa, client_key_der_1024, keySz); if (ret != 0) { printf("mcapi rsa private key decode failed\n"); return -1; } ret = RsaPrivateKeyDecode(client_key_der_1024, &idx, &defRsa, keySz); if (ret != 0) { printf("default rsa private key decode failed\n"); return -1; } ret = CRYPT_RSA_PublicEncrypt(&mcRsa, out1, sizeof(out1), ourData, RSA_TEST_SIZE, &mcRng); if (ret < 0) { printf("mcapi rsa public encrypt failed\n"); return -1; } ret2 = RsaPublicEncrypt(ourData, RSA_TEST_SIZE, out2, sizeof(out2), &defRsa, &defRng); if (ret2 < 0) { printf("default rsa public encrypt failed\n"); return -1; } if (ret != ret2) { printf("default rsa public encrypt sz != mcapi sz\n"); return -1; } if (ret != CRYPT_RSA_EncryptSizeGet(&mcRsa)) { printf("mcapi encrypt sz get != mcapi sz\n"); return -1; } ret = CRYPT_RSA_PrivateDecrypt(&mcRsa, out2, sizeof(out2), out1, ret); if (ret < 0) { printf("mcapi rsa private derypt failed\n"); return -1; } if (ret != RSA_TEST_SIZE) { printf("mcapi rsa private derypt plain size wrong\n"); return -1; } if (memcmp(out2, ourData, ret) != 0) { printf("mcapi rsa private derypt plain text bad\n"); return -1; } FreeRsaKey(&defRsa); ret = CRYPT_RSA_Free(&mcRsa); if (ret != 0) { printf("mcapi rsa free failed\n"); return -1; } printf("rsa mcapi test passed\n"); return 0; }
void bench_rsa(void) { int i; int ret; byte tmp[3072]; size_t bytes; word32 idx = 0; byte message[] = "Everyone gets Friday off."; byte enc[512]; /* for up to 4096 bit */ const int len = (int)strlen((char*)message); double start, total, each, milliEach; RsaKey rsaKey; int rsaKeySz = 2048; /* used in printf */ #ifdef USE_CERT_BUFFERS_1024 XMEMCPY(tmp, rsa_key_der_1024, sizeof_rsa_key_der_1024); bytes = sizeof_rsa_key_der_1024; rsaKeySz = 1024; #elif defined(USE_CERT_BUFFERS_2048) XMEMCPY(tmp, rsa_key_der_2048, sizeof_rsa_key_der_2048); bytes = sizeof_rsa_key_der_2048; #else FILE* file = fopen(certRSAname, "rb"); if (!file) { printf("can't find %s, Please run from CyaSSL home dir\n", certRSAname); return; } bytes = fread(tmp, 1, sizeof(tmp), file); fclose(file); #endif /* USE_CERT_BUFFERS */ #ifdef HAVE_CAVIUM if (RsaInitCavium(&rsaKey, CAVIUM_DEV_ID) != 0) printf("RSA init cavium failed\n"); #endif ret = InitRng(&rng); if (ret < 0) { printf("InitRNG failed\n"); return; } ret = InitRsaKey(&rsaKey, 0); if (ret < 0) { printf("InitRsaKey failed\n"); return; } ret = RsaPrivateKeyDecode(tmp, &idx, &rsaKey, (word32)bytes); start = current_time(1); for (i = 0; i < ntimes; i++) ret = RsaPublicEncrypt(message,len,enc,sizeof(enc), &rsaKey, &rng); total = current_time(0) - start; each = total / ntimes; /* per second */ milliEach = each * 1000; /* milliseconds */ printf("RSA %d encryption took %6.3f milliseconds, avg over %d" " iterations\n", rsaKeySz, milliEach, ntimes); if (ret < 0) { printf("Rsa Public Encrypt failed\n"); return; } start = current_time(1); for (i = 0; i < ntimes; i++) { byte out[512]; /* for up to 4096 bit */ RsaPrivateDecrypt(enc, (word32)ret, out, sizeof(out), &rsaKey); } total = current_time(0) - start; each = total / ntimes; /* per second */ milliEach = each * 1000; /* milliseconds */ printf("RSA %d decryption took %6.3f milliseconds, avg over %d" " iterations\n", rsaKeySz, milliEach, ntimes); FreeRsaKey(&rsaKey); #ifdef HAVE_CAVIUM RsaFreeCavium(&rsaKey); #endif }
int rsa_test() { byte tmp[1024], tmp2[2048]; size_t bytes, bytes2; RsaKey key; RNG rng; word32 idx = 0; int ret; byte in[] = "Everyone gets Friday off."; word32 inLen = (word32)strlen((char*)in); byte out[64]; byte plain[64]; DecodedCert cert; FILE* file = fopen(clientKey, "rb"), * file2; if (!file) return -40; bytes = fread(tmp, 1, 1024, file); InitRsaKey(&key, 0); ret = RsaPrivateKeyDecode(tmp, &idx, &key, (word32)bytes); if (ret != 0) return -41; ret = InitRng(&rng); if (ret != 0) return -42; ret = RsaPublicEncrypt(in, inLen, out, sizeof(out), &key, &rng); ret = RsaPrivateDecrypt(out, 64, plain, sizeof(plain), &key); if (memcmp(plain, in, inLen)) return -45; ret = RsaSSL_Sign(in, inLen, out, sizeof(out), &key, &rng); memset(plain, 0, sizeof(plain)); ret = RsaSSL_Verify(out, 64, plain, sizeof(plain), &key); if (memcmp(plain, in, ret)) return -46; file2 = fopen(clientCert, "rb"); if (!file2) return -47; bytes2 = fread(tmp2, 1, 2048, file2); InitDecodedCert(&cert, (byte*)&tmp2, 0); ret = ParseCert(&cert, (word32)bytes2, CERT_TYPE, NO_VERIFY, 0); if (ret != 0) return -48; FreeDecodedCert(&cert); fclose(file2); fclose(file); #ifdef CYASSL_KEY_GEN { byte der[4096]; byte pem[4096]; word32 derSz = 0; word32 pemSz = 0; RsaKey derIn; RsaKey genKey; FILE* keyFile; FILE* pemFile; InitRsaKey(&genKey, 0); ret = MakeRsaKey(&genKey, 1024, 65537, &rng); if (ret != 0) return -301; derSz = RsaKeyToDer(&genKey, der, sizeof(der)); if (derSz < 0) return -302; keyFile = fopen("./ker.der", "wb"); if (!keyFile) return -303; ret = fwrite(der, derSz, 1, keyFile); fclose(keyFile); pemSz = DerToPem(der, derSz, pem, sizeof(pem), PRIVATEKEY_TYPE); if (pemSz < 0) return -304; pemFile = fopen("./key.pem", "wb"); if (!pemFile) return -305; ret = fwrite(pem, pemSz, 1, pemFile); fclose(pemFile); InitRsaKey(&derIn, 0); idx = 0; ret = RsaPrivateKeyDecode(der, &idx, &derIn, derSz); if (ret != 0) return -306; } #endif /* CYASSL_KEY_GEN */ #ifdef CYASSL_CERT_GEN { Cert myCert; byte derCert[4096]; byte pem[4096]; DecodedCert decode; FILE* derFile; FILE* pemFile; int certSz; int pemSz; InitCert(&myCert); strncpy(myCert.subject.country, "US", NAME_SIZE); strncpy(myCert.subject.state, "OR", NAME_SIZE); strncpy(myCert.subject.locality, "Portland", NAME_SIZE); strncpy(myCert.subject.org, "yaSSL", NAME_SIZE); strncpy(myCert.subject.unit, "Development", NAME_SIZE); strncpy(myCert.subject.commonName, "www.yassl.com", NAME_SIZE); strncpy(myCert.subject.email, "*****@*****.**", NAME_SIZE); certSz = MakeCert(&myCert, derCert, sizeof(derCert), &key, &rng); if (certSz < 0) return -401; InitDecodedCert(&decode, derCert, 0); ret = ParseCert(&decode, certSz, CERT_TYPE, NO_VERIFY, 0); if (ret != 0) return -402; derFile = fopen("./cert.der", "wb"); if (!derFile) return -403; ret = fwrite(derCert, certSz, 1, derFile); fclose(derFile); pemSz = DerToPem(derCert, certSz, pem, sizeof(pem), CERT_TYPE); if (pemSz < 0) return -404; pemFile = fopen("./cert.pem", "wb"); if (!pemFile) return -405; ret = fwrite(pem, pemSz, 1, pemFile); fclose(pemFile); FreeDecodedCert(&decode); } #endif /* CYASSL_CERT_GEN */ FreeRsaKey(&key); return 0; }
/* create ASN.1 fomatted RecipientInfo structure, returns sequence size */ CYASSL_LOCAL int CreateRecipientInfo(const byte* cert, word32 certSz, int keyEncAlgo, int blockKeySz, RNG* rng, byte* contentKeyPlain, byte* contentKeyEnc, int* keyEncSz, byte* out, word32 outSz) { word32 idx = 0; int ret = 0, totalSz = 0; int verSz, issuerSz, snSz, keyEncAlgSz; int issuerSeqSz, recipSeqSz, issuerSerialSeqSz; int encKeyOctetStrSz; byte ver[MAX_VERSION_SZ]; byte serial[MAX_SN_SZ]; byte issuerSerialSeq[MAX_SEQ_SZ]; byte recipSeq[MAX_SEQ_SZ]; byte issuerSeq[MAX_SEQ_SZ]; byte keyAlgArray[MAX_ALGO_SZ]; byte encKeyOctetStr[MAX_OCTET_STR_SZ]; RsaKey pubKey; DecodedCert decoded; InitDecodedCert(&decoded, (byte*)cert, certSz, 0); ret = ParseCert(&decoded, CA_TYPE, NO_VERIFY, 0); if (ret < 0) { FreeDecodedCert(&decoded); return ret; } /* version */ verSz = SetMyVersion(0, ver, 0); /* IssuerAndSerialNumber */ if (decoded.issuerRaw == NULL || decoded.issuerRawLen == 0) { CYASSL_MSG("DecodedCert lacks raw issuer pointer and length"); FreeDecodedCert(&decoded); return -1; } issuerSz = decoded.issuerRawLen; issuerSeqSz = SetSequence(issuerSz, issuerSeq); if (decoded.serial == NULL || decoded.serialSz == 0) { CYASSL_MSG("DecodedCert missing serial number"); FreeDecodedCert(&decoded); return -1; } snSz = SetSerialNumber(decoded.serial, decoded.serialSz, serial); issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz, issuerSerialSeq); /* KeyEncryptionAlgorithmIdentifier, only support RSA now */ if (keyEncAlgo != RSAk) return ALGO_ID_E; keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, keyType, 0); if (keyEncAlgSz == 0) return BAD_FUNC_ARG; /* EncryptedKey */ ret = InitRsaKey(&pubKey, 0); if (ret != 0) return ret; if (RsaPublicKeyDecode(decoded.publicKey, &idx, &pubKey, decoded.pubKeySize) < 0) { CYASSL_MSG("ASN RSA key decode error"); return PUBLIC_KEY_E; } *keyEncSz = RsaPublicEncrypt(contentKeyPlain, blockKeySz, contentKeyEnc, MAX_ENCRYPTED_KEY_SZ, &pubKey, rng); FreeRsaKey(&pubKey); if (*keyEncSz < 0) { CYASSL_MSG("RSA Public Encrypt failed"); return *keyEncSz; } encKeyOctetStrSz = SetOctetString(*keyEncSz, encKeyOctetStr); /* RecipientInfo */ recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz + issuerSz + snSz + keyEncAlgSz + encKeyOctetStrSz + *keyEncSz, recipSeq); if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz + keyEncAlgSz + encKeyOctetStrSz + *keyEncSz > (int)outSz) { CYASSL_MSG("RecipientInfo output buffer too small"); return BUFFER_E; } XMEMCPY(out + totalSz, recipSeq, recipSeqSz); totalSz += recipSeqSz; XMEMCPY(out + totalSz, ver, verSz); totalSz += verSz; XMEMCPY(out + totalSz, issuerSerialSeq, issuerSerialSeqSz); totalSz += issuerSerialSeqSz; XMEMCPY(out + totalSz, issuerSeq, issuerSeqSz); totalSz += issuerSeqSz; XMEMCPY(out + totalSz, decoded.issuerRaw, issuerSz); totalSz += issuerSz; XMEMCPY(out + totalSz, serial, snSz); totalSz += snSz; XMEMCPY(out + totalSz, keyAlgArray, keyEncAlgSz); totalSz += keyEncAlgSz; XMEMCPY(out + totalSz, encKeyOctetStr, encKeyOctetStrSz); totalSz += encKeyOctetStrSz; XMEMCPY(out + totalSz, contentKeyEnc, *keyEncSz); totalSz += *keyEncSz; FreeDecodedCert(&decoded); return totalSz; }
/* Finds the certificates in the message and saves it. */ int PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) { word32 idx, contentType; int length, version, ret; byte* content = NULL; byte* sig = NULL; byte* cert = NULL; byte* signedAttr = NULL; int contentSz = 0, sigSz = 0, certSz = 0, signedAttrSz = 0; (void)signedAttr; /* not used yet, just set */ (void)signedAttrSz; if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0) return BAD_FUNC_ARG; idx = 0; /* Get the contentInfo sequence */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the contentInfo contentType */ if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (contentType != SIGNED_DATA) { CYASSL_MSG("PKCS#7 input not of type SignedData"); return PKCS7_OID_E; } /* get the ContentInfo content */ if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the signedData sequence */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the version */ if (GetMyVersion(pkiMsg, &idx, &version) < 0) return ASN_PARSE_E; if (version != 1) { CYASSL_MSG("PKCS#7 signedData needs to be of version 1"); return ASN_VERSION_E; } /* Get the set of DigestAlgorithmIdentifiers */ if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip the set. */ idx += length; /* Get the inner ContentInfo sequence */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the inner ContentInfo contentType */ if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (contentType != DATA) { CYASSL_MSG("PKCS#7 inner input not of type Data"); return PKCS7_OID_E; } if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (pkiMsg[idx++] != ASN_OCTET_STRING) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Save the inner data as the content. */ if (length > 0) { /* Local pointer for calculating hashes later */ pkcs7->content = content = &pkiMsg[idx]; pkcs7->contentSz = contentSz = length; idx += length; } /* Get the implicit[0] set of certificates */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (length > 0) { /* At this point, idx is at the first certificate in * a set of certificates. There may be more than one, * or none, or they may be a PKCS 6 extended * certificate. We want to save the first cert if it * is X.509. */ word32 certIdx = idx; if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { if (GetLength(pkiMsg, &certIdx, &certSz, pkiMsgSz) < 0) return ASN_PARSE_E; cert = &pkiMsg[idx]; certSz += (certIdx - idx); } PKCS7_InitWithCert(pkcs7, cert, certSz); } idx += length; } /* Get the implicit[1] set of crls */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip the set */ idx += length; } /* Get the set of signerInfos */ if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (length > 0) { RsaKey key; word32 scratch = 0; int plainSz = 0; byte digest[MAX_SEQ_SZ+MAX_ALGO_SZ+MAX_OCTET_STR_SZ+SHA_DIGEST_SIZE]; /* Get the sequence of the first signerInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Get the version */ if (GetMyVersion(pkiMsg, &idx, &version) < 0) return ASN_PARSE_E; if (version != 1) { CYASSL_MSG("PKCS#7 signerInfo needs to be of version 1"); return ASN_VERSION_E; } /* Get the sequence of IssuerAndSerialNumber */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip it */ idx += length; /* Get the sequence of digestAlgorithm */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip it */ idx += length; /* Get the IMPLICIT[0] SET OF signedAttributes */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* save pointer and length */ signedAttr = &pkiMsg[idx]; signedAttrSz = length; idx += length; } /* Get the sequence of digestEncryptionAlgorithm */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* Skip it */ idx += length; /* Get the signature */ if (pkiMsg[idx] == ASN_OCTET_STRING) { idx++; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* save pointer and length */ sig = &pkiMsg[idx]; sigSz = length; idx += length; } XMEMSET(digest, 0, sizeof(digest)); pkcs7->content = content; pkcs7->contentSz = contentSz; ret = InitRsaKey(&key, NULL); if (ret != 0) return ret; if (RsaPublicKeyDecode(pkcs7->publicKey, &scratch, &key, pkcs7->publicKeySz) < 0) { CYASSL_MSG("ASN RSA key decode error"); return PUBLIC_KEY_E; } plainSz = RsaSSL_Verify(sig, sigSz, digest, sizeof(digest), &key); FreeRsaKey(&key); if (plainSz < 0) return plainSz; } return 0; }
/* build PKCS#7 signedData content type */ int PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) { static const byte outerOid[] = { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 }; static const byte innerOid[] = { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; ESD esd; word32 signerInfoSz = 0; word32 totalSz = 0; int idx = 0, ret = 0; byte* flatSignedAttribs = NULL; word32 flatSignedAttribsSz = 0; word32 innerOidSz = sizeof(innerOid); word32 outerOidSz = sizeof(outerOid); if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0 || output == NULL || outputSz == 0) return BAD_FUNC_ARG; XMEMSET(&esd, 0, sizeof(esd)); ret = InitSha(&esd.sha); if (ret != 0) return ret; if (pkcs7->contentSz != 0) { ShaUpdate(&esd.sha, pkcs7->content, pkcs7->contentSz); esd.contentDigest[0] = ASN_OCTET_STRING; esd.contentDigest[1] = SHA_DIGEST_SIZE; ShaFinal(&esd.sha, &esd.contentDigest[2]); } esd.innerOctetsSz = SetOctetString(pkcs7->contentSz, esd.innerOctets); esd.innerContSeqSz = SetExplicit(0, esd.innerOctetsSz + pkcs7->contentSz, esd.innerContSeq); esd.contentInfoSeqSz = SetSequence(pkcs7->contentSz + esd.innerOctetsSz + innerOidSz + esd.innerContSeqSz, esd.contentInfoSeq); esd.issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz, esd.issuerSn); signerInfoSz += esd.issuerSnSz; esd.issuerNameSz = SetSequence(pkcs7->issuerSz, esd.issuerName); signerInfoSz += esd.issuerNameSz + pkcs7->issuerSz; esd.issuerSnSeqSz = SetSequence(signerInfoSz, esd.issuerSnSeq); signerInfoSz += esd.issuerSnSeqSz; esd.signerVersionSz = SetMyVersion(1, esd.signerVersion, 0); signerInfoSz += esd.signerVersionSz; esd.signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd.signerDigAlgoId, hashType, 0); signerInfoSz += esd.signerDigAlgoIdSz; esd.digEncAlgoIdSz = SetAlgoID(pkcs7->encryptOID, esd.digEncAlgoId, keyType, 0); signerInfoSz += esd.digEncAlgoIdSz; if (pkcs7->signedAttribsSz != 0) { byte contentTypeOid[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, 0x09, 0x03 }; byte contentType[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 }; byte messageDigestOid[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04 }; PKCS7Attrib cannedAttribs[2] = { { contentTypeOid, sizeof(contentTypeOid), contentType, sizeof(contentType) }, { messageDigestOid, sizeof(messageDigestOid), esd.contentDigest, sizeof(esd.contentDigest) } }; word32 cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib); esd.signedAttribsCount += cannedAttribsCount; esd.signedAttribsSz += EncodeAttributes(&esd.signedAttribs[0], 2, cannedAttribs, cannedAttribsCount); esd.signedAttribsCount += pkcs7->signedAttribsSz; esd.signedAttribsSz += EncodeAttributes(&esd.signedAttribs[2], 4, pkcs7->signedAttribs, pkcs7->signedAttribsSz); flatSignedAttribs = (byte*)XMALLOC(esd.signedAttribsSz, 0, NULL); flatSignedAttribsSz = esd.signedAttribsSz; if (flatSignedAttribs == NULL) return MEMORY_E; FlattenAttributes(flatSignedAttribs, esd.signedAttribs, esd.signedAttribsCount); esd.signedAttribSetSz = SetImplicit(ASN_SET, 0, esd.signedAttribsSz, esd.signedAttribSet); } /* Calculate the final hash and encrypt it. */ { RsaKey privKey; int result; word32 scratch = 0; byte digestInfo[MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE]; byte digestInfoSeq[MAX_SEQ_SZ]; byte digestStr[MAX_OCTET_STR_SZ]; word32 digestInfoSeqSz, digestStrSz; int digIdx = 0; if (pkcs7->signedAttribsSz != 0) { byte attribSet[MAX_SET_SZ]; word32 attribSetSz; attribSetSz = SetSet(flatSignedAttribsSz, attribSet); ret = InitSha(&esd.sha); if (ret < 0) { XFREE(flatSignedAttribs, 0, NULL); return ret; } ShaUpdate(&esd.sha, attribSet, attribSetSz); ShaUpdate(&esd.sha, flatSignedAttribs, flatSignedAttribsSz); } ShaFinal(&esd.sha, esd.contentAttribsDigest); digestStrSz = SetOctetString(SHA_DIGEST_SIZE, digestStr); digestInfoSeqSz = SetSequence(esd.signerDigAlgoIdSz + digestStrSz + SHA_DIGEST_SIZE, digestInfoSeq); XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz); digIdx += digestInfoSeqSz; XMEMCPY(digestInfo + digIdx, esd.signerDigAlgoId, esd.signerDigAlgoIdSz); digIdx += esd.signerDigAlgoIdSz; XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz); digIdx += digestStrSz; XMEMCPY(digestInfo + digIdx, esd.contentAttribsDigest, SHA_DIGEST_SIZE); digIdx += SHA_DIGEST_SIZE; result = InitRsaKey(&privKey, NULL); if (result == 0) result = RsaPrivateKeyDecode(pkcs7->privateKey, &scratch, &privKey, pkcs7->privateKeySz); if (result < 0) { XFREE(flatSignedAttribs, 0, NULL); return PUBLIC_KEY_E; } result = RsaSSL_Sign(digestInfo, digIdx, esd.encContentDigest, sizeof(esd.encContentDigest), &privKey, pkcs7->rng); FreeRsaKey(&privKey); if (result < 0) { XFREE(flatSignedAttribs, 0, NULL); return result; } esd.encContentDigestSz = (word32)result; } signerInfoSz += flatSignedAttribsSz + esd.signedAttribSetSz; esd.signerDigestSz = SetOctetString(esd.encContentDigestSz, esd.signerDigest); signerInfoSz += esd.signerDigestSz + esd.encContentDigestSz; esd.signerInfoSeqSz = SetSequence(signerInfoSz, esd.signerInfoSeq); signerInfoSz += esd.signerInfoSeqSz; esd.signerInfoSetSz = SetSet(signerInfoSz, esd.signerInfoSet); signerInfoSz += esd.signerInfoSetSz; esd.certsSetSz = SetImplicit(ASN_SET, 0, pkcs7->singleCertSz, esd.certsSet); esd.singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd.singleDigAlgoId, hashType, 0); esd.digAlgoIdSetSz = SetSet(esd.singleDigAlgoIdSz, esd.digAlgoIdSet); esd.versionSz = SetMyVersion(1, esd.version, 0); totalSz = esd.versionSz + esd.singleDigAlgoIdSz + esd.digAlgoIdSetSz + esd.contentInfoSeqSz + esd.certsSetSz + pkcs7->singleCertSz + esd.innerOctetsSz + esd.innerContSeqSz + innerOidSz + pkcs7->contentSz + signerInfoSz; esd.innerSeqSz = SetSequence(totalSz, esd.innerSeq); totalSz += esd.innerSeqSz; esd.outerContentSz = SetExplicit(0, totalSz, esd.outerContent); totalSz += esd.outerContentSz + outerOidSz; esd.outerSeqSz = SetSequence(totalSz, esd.outerSeq); totalSz += esd.outerSeqSz; if (outputSz < totalSz) return BUFFER_E; idx = 0; XMEMCPY(output + idx, esd.outerSeq, esd.outerSeqSz); idx += esd.outerSeqSz; XMEMCPY(output + idx, outerOid, outerOidSz); idx += outerOidSz; XMEMCPY(output + idx, esd.outerContent, esd.outerContentSz); idx += esd.outerContentSz; XMEMCPY(output + idx, esd.innerSeq, esd.innerSeqSz); idx += esd.innerSeqSz; XMEMCPY(output + idx, esd.version, esd.versionSz); idx += esd.versionSz; XMEMCPY(output + idx, esd.digAlgoIdSet, esd.digAlgoIdSetSz); idx += esd.digAlgoIdSetSz; XMEMCPY(output + idx, esd.singleDigAlgoId, esd.singleDigAlgoIdSz); idx += esd.singleDigAlgoIdSz; XMEMCPY(output + idx, esd.contentInfoSeq, esd.contentInfoSeqSz); idx += esd.contentInfoSeqSz; XMEMCPY(output + idx, innerOid, innerOidSz); idx += innerOidSz; XMEMCPY(output + idx, esd.innerContSeq, esd.innerContSeqSz); idx += esd.innerContSeqSz; XMEMCPY(output + idx, esd.innerOctets, esd.innerOctetsSz); idx += esd.innerOctetsSz; XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); idx += pkcs7->contentSz; XMEMCPY(output + idx, esd.certsSet, esd.certsSetSz); idx += esd.certsSetSz; XMEMCPY(output + idx, pkcs7->singleCert, pkcs7->singleCertSz); idx += pkcs7->singleCertSz; XMEMCPY(output + idx, esd.signerInfoSet, esd.signerInfoSetSz); idx += esd.signerInfoSetSz; XMEMCPY(output + idx, esd.signerInfoSeq, esd.signerInfoSeqSz); idx += esd.signerInfoSeqSz; XMEMCPY(output + idx, esd.signerVersion, esd.signerVersionSz); idx += esd.signerVersionSz; XMEMCPY(output + idx, esd.issuerSnSeq, esd.issuerSnSeqSz); idx += esd.issuerSnSeqSz; XMEMCPY(output + idx, esd.issuerName, esd.issuerNameSz); idx += esd.issuerNameSz; XMEMCPY(output + idx, pkcs7->issuer, pkcs7->issuerSz); idx += pkcs7->issuerSz; XMEMCPY(output + idx, esd.issuerSn, esd.issuerSnSz); idx += esd.issuerSnSz; XMEMCPY(output + idx, esd.signerDigAlgoId, esd.signerDigAlgoIdSz); idx += esd.signerDigAlgoIdSz; /* SignerInfo:Attributes */ if (pkcs7->signedAttribsSz != 0) { XMEMCPY(output + idx, esd.signedAttribSet, esd.signedAttribSetSz); idx += esd.signedAttribSetSz; XMEMCPY(output + idx, flatSignedAttribs, flatSignedAttribsSz); idx += flatSignedAttribsSz; XFREE(flatSignedAttribs, 0, NULL); } XMEMCPY(output + idx, esd.digEncAlgoId, esd.digEncAlgoIdSz); idx += esd.digEncAlgoIdSz; XMEMCPY(output + idx, esd.signerDigest, esd.signerDigestSz); idx += esd.signerDigestSz; XMEMCPY(output + idx, esd.encContentDigest, esd.encContentDigestSz); idx += esd.encContentDigestSz; return idx; }
/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ CYASSL_API int PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, byte* output, word32 outputSz) { int recipFound = 0; int ret, version, length; word32 savedIdx = 0, idx = 0; word32 contentType, encOID; byte issuerHash[SHA_DIGEST_SIZE]; mp_int serialNum; int encryptedKeySz, keySz; byte tmpIv[DES_BLOCK_SIZE]; byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; byte* decryptedKey = NULL; RsaKey privKey; int encryptedContentSz; byte padLen; byte* encryptedContent = NULL; if (pkcs7 == NULL || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0) return BAD_FUNC_ARG; if (pkiMsg == NULL || pkiMsgSz == 0 || output == NULL || outputSz == 0) return BAD_FUNC_ARG; /* load private key */ ret = InitRsaKey(&privKey, 0); if (ret != 0) return ret; ret = RsaPrivateKeyDecode(pkcs7->privateKey, &idx, &privKey, pkcs7->privateKeySz); if (ret != 0) { CYASSL_MSG("Failed to decode RSA private key"); return ret; } idx = 0; /* read past ContentInfo, verify type is envelopedData */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (contentType != ENVELOPED_DATA) { CYASSL_MSG("PKCS#7 input not of type EnvelopedData"); return PKCS7_OID_E; } if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* remove EnvelopedData and version */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetMyVersion(pkiMsg, &idx, &version) < 0) return ASN_PARSE_E; if (version != 0) { CYASSL_MSG("PKCS#7 envelopedData needs to be of version 0"); return ASN_VERSION_E; } /* walk through RecipientInfo set, find correct recipient */ if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; savedIdx = idx; recipFound = 0; /* when looking for next recipient, use first sequence and version to * indicate there is another, if not, move on */ while(recipFound == 0) { /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to * last good saved one */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { idx = savedIdx; break; } if (GetMyVersion(pkiMsg, &idx, &version) < 0) { idx = savedIdx; break; } if (version != 0) return ASN_VERSION_E; /* remove IssuerAndSerialNumber */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) return ASN_PARSE_E; /* if we found correct recipient, issuer hashes will match */ if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) { recipFound = 1; } if (GetInt(&serialNum, pkiMsg, &idx, pkiMsgSz) < 0) return ASN_PARSE_E; mp_clear(&serialNum); if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) return ASN_PARSE_E; /* key encryption algorithm must be RSA for now */ if (encOID != RSAk) return ALGO_ID_E; /* read encryptedKey */ if (pkiMsg[idx++] != ASN_OCTET_STRING) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) return ASN_PARSE_E; if (recipFound == 1) XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz); idx += encryptedKeySz; /* update good idx */ savedIdx = idx; } if (recipFound == 0) { CYASSL_MSG("No recipient found in envelopedData that matches input"); return PKCS7_RECIP_E; } /* remove EncryptedContentInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) return ASN_PARSE_E; /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ if (pkiMsg[idx++] != ASN_OCTET_STRING) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (length != DES_BLOCK_SIZE) { CYASSL_MSG("Incorrect IV length, must be of DES_BLOCK_SIZE"); return ASN_PARSE_E; } XMEMCPY(tmpIv, &pkiMsg[idx], length); idx += length; /* read encryptedContent, cont[0] */ if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) return ASN_PARSE_E; encryptedContent = XMALLOC(encryptedContentSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); /* decrypt encryptedKey */ keySz = RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, &decryptedKey, &privKey); FreeRsaKey(&privKey); if (keySz <= 0) return keySz; /* decrypt encryptedContent */ if (encOID == DESb) { Des des; ret = Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); if (ret == 0) Des_CbcDecrypt(&des, encryptedContent, encryptedContent, encryptedContentSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } } else if (encOID == DES3b) { Des3 des; ret = Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); if (ret == 0) ret = Des3_CbcDecrypt(&des, encryptedContent, encryptedContent, encryptedContentSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } } else { CYASSL_MSG("Unsupported content encryption OID type"); return ALGO_ID_E; } padLen = encryptedContent[encryptedContentSz-1]; /* copy plaintext to output */ XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); /* free memory, zero out keys */ XMEMSET(encryptedKey, 0, MAX_ENCRYPTED_KEY_SZ); XMEMSET(encryptedContent, 0, encryptedContentSz); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); return encryptedContentSz - padLen; }