static EVP_PKEY *getPrivateKey(PKCS12 *p12, X509 *x509, const char* pass) { // Extract all PKCS7 safes STACK_OF(PKCS7) *pkcs7s = PKCS12_unpack_authsafes(p12); if (!pkcs7s) { certutil_updateErrorString(); return NULL; } // For each PKCS7 safe int nump = sk_PKCS7_num(pkcs7s); for (int p = 0; p < nump; p++) { PKCS7 *p7 = sk_PKCS7_value(pkcs7s, p); if (!p7) continue; STACK_OF(PKCS12_SAFEBAG) *safebags = PKCS12_unpack_p7data(p7); if (!safebags) continue; // For each PKCS12 safebag int numb = sk_PKCS12_SAFEBAG_num(safebags); for (int i = 0; i < numb; i++) { PKCS12_SAFEBAG *bag = sk_PKCS12_SAFEBAG_value(safebags, i); if (!bag) continue; switch (M_PKCS12_bag_type(bag)) { case NID_pkcs8ShroudedKeyBag:; // Encrypted key PKCS8_PRIV_KEY_INFO *p8 = PKCS12_decrypt_skey(bag, pass, strlen(pass)); if (p8) { EVP_PKEY *pk = EVP_PKCS82PKEY(p8); PKCS8_PRIV_KEY_INFO_free(p8); if (!pk) break; // out of switch if (X509_check_private_key(x509, pk) > 0) { sk_PKCS12_SAFEBAG_pop_free(safebags, PKCS12_SAFEBAG_free); sk_PKCS7_pop_free(pkcs7s, PKCS7_free); return pk; } EVP_PKEY_free(pk); } break; } } sk_PKCS12_SAFEBAG_pop_free(safebags, PKCS12_SAFEBAG_free); } sk_PKCS7_pop_free(pkcs7s, PKCS7_free); return NULL; }
static void add_from_bag(X509 **pX509, EVP_PKEY **pPkey, PKCS12_SAFEBAG *bag, const char *pw) { EVP_PKEY *pkey = NULL; X509 *x509 = NULL; PKCS8_PRIV_KEY_INFO *p8 = NULL; switch (M_PKCS12_bag_type(bag)) { case NID_keyBag: p8 = bag->value.keybag; pkey = EVP_PKCS82PKEY(p8); break; case NID_pkcs8ShroudedKeyBag: p8 = PKCS12_decrypt_skey(bag, pw, (int)strlen(pw)); if (p8) { pkey = EVP_PKCS82PKEY(p8); PKCS8_PRIV_KEY_INFO_free(p8); } break; case NID_certBag: if (M_PKCS12_cert_bag_type(bag) == NID_x509Certificate) x509 = PKCS12_certbag2x509(bag); break; case NID_safeContentsBag: add_from_bags(pX509, pPkey, bag->value.safes, pw); break; } if (pkey) { if (!*pPkey) *pPkey = pkey; else EVP_PKEY_free(pkey); } if (x509) { if (!*pX509) *pX509 = x509; else X509_free(x509); } }