ASN1_OCTET_STRING * PKCS12_item_i2d_encrypt(X509_ALGOR *algor, const ASN1_ITEM *it, const char *pass, int passlen, void *obj, int zbuf) { ASN1_OCTET_STRING *oct; unsigned char *in = NULL; int inlen; if (!(oct = ASN1_OCTET_STRING_new ())) { PKCS12error(ERR_R_MALLOC_FAILURE); return NULL; } inlen = ASN1_item_i2d(obj, &in, it); if (!in) { PKCS12error(PKCS12_R_ENCODE_ERROR); goto err; } if (!PKCS12_pbe_crypt(algor, pass, passlen, in, inlen, &oct->data, &oct->length, 1)) { PKCS12error(PKCS12_R_ENCRYPT_ERROR); goto err; } if (zbuf) explicit_bzero(in, inlen); free(in); return oct; err: free(in); ASN1_OCTET_STRING_free(oct); return NULL; }
int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type) { int ret; unsigned char *unipass; int uniplen; if (!pass) { unipass = NULL; uniplen = 0; } else if (!OPENSSL_asc2uni(pass, passlen, &unipass, &uniplen)) { PKCS12error(ERR_R_MALLOC_FAILURE); return 0; } ret = PKCS12_key_gen_uni(unipass, uniplen, salt, saltlen, id, iter, n, out, md_type); if (ret <= 0) return 0; if (unipass) { explicit_bzero(unipass, uniplen); free(unipass); } return ret; }
unsigned char * PKCS12_pbe_crypt(X509_ALGOR *algor, const char *pass, int passlen, unsigned char *in, int inlen, unsigned char **data, int *datalen, int en_de) { unsigned char *out; int outlen, i; EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX_init(&ctx); /* Decrypt data */ if (!EVP_PBE_CipherInit(algor->algorithm, pass, passlen, algor->parameter, &ctx, en_de)) { out = NULL; PKCS12error(PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR); goto err; } if (!(out = malloc(inlen + EVP_CIPHER_CTX_block_size(&ctx)))) { PKCS12error(ERR_R_MALLOC_FAILURE); goto err; } if (!EVP_CipherUpdate(&ctx, out, &i, in, inlen)) { free(out); out = NULL; PKCS12error(ERR_R_EVP_LIB); goto err; } outlen = i; if (!EVP_CipherFinal_ex(&ctx, out + i, &i)) { free(out); out = NULL; PKCS12error(PKCS12_R_PKCS12_CIPHERFINAL_ERROR); goto err; } outlen += i; if (datalen) *datalen = outlen; if (data) *data = out; err: EVP_CIPHER_CTX_cleanup(&ctx); return out; }
/* Generate a MAC */ int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, unsigned char *mac, unsigned int *maclen) { const EVP_MD *md_type; HMAC_CTX hmac; unsigned char key[EVP_MAX_MD_SIZE], *salt; int saltlen, iter; int md_size; if (!PKCS7_type_is_data(p12->authsafes)) { PKCS12error(PKCS12_R_CONTENT_TYPE_NOT_DATA); return 0; } salt = p12->mac->salt->data; saltlen = p12->mac->salt->length; if (!p12->mac->iter) iter = 1; else if ((iter = ASN1_INTEGER_get(p12->mac->iter)) <= 0) { PKCS12error(PKCS12_R_DECODE_ERROR); return 0; } if (!(md_type = EVP_get_digestbyobj( p12->mac->dinfo->algor->algorithm))) { PKCS12error(PKCS12_R_UNKNOWN_DIGEST_ALGORITHM); return 0; } md_size = EVP_MD_size(md_type); if (md_size < 0) return 0; if (!PKCS12_key_gen(pass, passlen, salt, saltlen, PKCS12_MAC_ID, iter, md_size, key, md_type)) { PKCS12error(PKCS12_R_KEY_GEN_ERROR); return 0; } HMAC_CTX_init(&hmac); if (!HMAC_Init_ex(&hmac, key, md_size, md_type, NULL) || !HMAC_Update(&hmac, p12->authsafes->d.data->data, p12->authsafes->d.data->length) || !HMAC_Final(&hmac, mac, maclen)) { HMAC_CTX_cleanup(&hmac); return 0; } HMAC_CTX_cleanup(&hmac); return 1; }
/* Verify the mac */ int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen) { unsigned char mac[EVP_MAX_MD_SIZE]; unsigned int maclen; if (p12->mac == NULL) { PKCS12error(PKCS12_R_MAC_ABSENT); return 0; } if (!PKCS12_gen_mac(p12, pass, passlen, mac, &maclen)) { PKCS12error(PKCS12_R_MAC_GENERATION_ERROR); return 0; } if ((maclen != (unsigned int)p12->mac->dinfo->digest->length) || memcmp(mac, p12->mac->dinfo->digest->data, maclen)) return 0; return 1; }
void * PKCS12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it, const char *pass, int passlen, ASN1_OCTET_STRING *oct, int zbuf) { unsigned char *out; const unsigned char *p; void *ret; int outlen; if (!PKCS12_pbe_crypt(algor, pass, passlen, oct->data, oct->length, &out, &outlen, 0)) { PKCS12error(PKCS12_R_PKCS12_PBE_CRYPT_ERROR); return NULL; } p = out; ret = ASN1_item_d2i(NULL, &p, outlen, it); if (zbuf) explicit_bzero(out, outlen); if (!ret) PKCS12error(PKCS12_R_DECODE_ERROR); free(out); return ret; }
X509_SIG * PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass, int passlen, unsigned char *salt, int saltlen, int iter, PKCS8_PRIV_KEY_INFO *p8inf) { X509_SIG *p8 = NULL; X509_ALGOR *pbe; if (!(p8 = X509_SIG_new())) { PKCS12error(ERR_R_MALLOC_FAILURE); goto err; } if (pbe_nid == -1) pbe = PKCS5_pbe2_set(cipher, iter, salt, saltlen); else pbe = PKCS5_pbe_set(pbe_nid, iter, salt, saltlen); if (!pbe) { PKCS12error(ERR_R_ASN1_LIB); goto err; } X509_ALGOR_free(p8->algor); p8->algor = pbe; ASN1_OCTET_STRING_free(p8->digest); p8->digest = PKCS12_item_i2d_encrypt(pbe, &PKCS8_PRIV_KEY_INFO_it, pass, passlen, p8inf, 1); if (!p8->digest) { PKCS12error(PKCS12_R_ENCRYPT_ERROR); goto err; } return p8; err: X509_SIG_free(p8); return NULL; }
/* Set up a mac structure */ int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, int saltlen, const EVP_MD *md_type) { if (!(p12->mac = PKCS12_MAC_DATA_new())) return PKCS12_ERROR; if (iter > 1) { if (!(p12->mac->iter = ASN1_INTEGER_new())) { PKCS12error(ERR_R_MALLOC_FAILURE); return 0; } if (!ASN1_INTEGER_set(p12->mac->iter, iter)) { PKCS12error(ERR_R_MALLOC_FAILURE); return 0; } } if (!saltlen) saltlen = PKCS12_SALT_LEN; if (!(p12->mac->salt->data = malloc(saltlen))) { PKCS12error(ERR_R_MALLOC_FAILURE); return 0; } p12->mac->salt->length = saltlen; if (!salt) arc4random_buf(p12->mac->salt->data, saltlen); else memcpy (p12->mac->salt->data, salt, saltlen); p12->mac->dinfo->algor->algorithm = OBJ_nid2obj(EVP_MD_type(md_type)); if (!(p12->mac->dinfo->algor->parameter = ASN1_TYPE_new())) { PKCS12error(ERR_R_MALLOC_FAILURE); return 0; } p12->mac->dinfo->algor->parameter->type = V_ASN1_NULL; return 1; }
int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen, unsigned char *salt, int saltlen, int iter, const EVP_MD *md_type) { unsigned char mac[EVP_MAX_MD_SIZE]; unsigned int maclen; if (!md_type) md_type = EVP_sha1(); if (PKCS12_setup_mac(p12, iter, salt, saltlen, md_type) == PKCS12_ERROR) { PKCS12error(PKCS12_R_MAC_SETUP_ERROR); return 0; } if (!PKCS12_gen_mac(p12, pass, passlen, mac, &maclen)) { PKCS12error(PKCS12_R_MAC_GENERATION_ERROR); return 0; } if (!(ASN1_STRING_set(p12->mac->dinfo->digest, mac, maclen))) { PKCS12error(PKCS12_R_MAC_STRING_SET_ERROR); return 0; } return 1; }
int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type) { unsigned char *B, *D, *I, *p, *Ai; int Slen, Plen, Ilen, Ijlen; int i, j, u, v; int ret = 0; BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */ EVP_MD_CTX ctx; v = EVP_MD_block_size(md_type); u = EVP_MD_size(md_type); if (u < 0) return 0; EVP_MD_CTX_init(&ctx); D = malloc(v); Ai = malloc(u); B = malloc(v + 1); Slen = v * ((saltlen + v - 1) / v); if (passlen) Plen = v * ((passlen + v - 1)/v); else Plen = 0; Ilen = Slen + Plen; I = malloc(Ilen); Ij = BN_new(); Bpl1 = BN_new(); if (!D || !Ai || !B || !I || !Ij || !Bpl1) goto err; for (i = 0; i < v; i++) D[i] = id; p = I; for (i = 0; i < Slen; i++) *p++ = salt[i % saltlen]; for (i = 0; i < Plen; i++) *p++ = pass[i % passlen]; for (;;) { if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || !EVP_DigestUpdate(&ctx, D, v) || !EVP_DigestUpdate(&ctx, I, Ilen) || !EVP_DigestFinal_ex(&ctx, Ai, NULL)) goto err; for (j = 1; j < iter; j++) { if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || !EVP_DigestUpdate(&ctx, Ai, u) || !EVP_DigestFinal_ex(&ctx, Ai, NULL)) goto err; } memcpy (out, Ai, min (n, u)); if (u >= n) { ret = 1; goto end; } n -= u; out += u; for (j = 0; j < v; j++) B[j] = Ai[j % u]; /* Work out B + 1 first then can use B as tmp space */ if (!BN_bin2bn (B, v, Bpl1)) goto err; if (!BN_add_word (Bpl1, 1)) goto err; for (j = 0; j < Ilen; j += v) { if (!BN_bin2bn(I + j, v, Ij)) goto err; if (!BN_add(Ij, Ij, Bpl1)) goto err; if (!BN_bn2bin(Ij, B)) goto err; Ijlen = BN_num_bytes (Ij); /* If more than 2^(v*8) - 1 cut off MSB */ if (Ijlen > v) { if (!BN_bn2bin (Ij, B)) goto err; memcpy (I + j, B + 1, v); #ifndef PKCS12_BROKEN_KEYGEN /* If less than v bytes pad with zeroes */ } else if (Ijlen < v) { memset(I + j, 0, v - Ijlen); if (!BN_bn2bin(Ij, I + j + v - Ijlen)) goto err; #endif } else if (!BN_bn2bin (Ij, I + j)) goto err; } } err: PKCS12error(ERR_R_MALLOC_FAILURE); end: free(Ai); free(B); free(D); free(I); BN_free(Ij); BN_free(Bpl1); EVP_MD_CTX_cleanup(&ctx); return ret; }