static int do_i2b_bio(BIO *out, EVP_PKEY *pk, int ispub) { unsigned char *tmp = NULL; int outlen, wrlen; outlen = do_i2b(&tmp, pk, ispub); if (outlen < 0) return -1; wrlen = BIO_write(out, tmp, outlen); OPENSSL_free(tmp); if (wrlen == outlen) return outlen; return -1; }
static int i2b_PVK(unsigned char **out, EVP_PKEY*pk, int enclevel, pem_password_cb *cb, void *u) { int outlen = 24, pklen; unsigned char *p, *salt = NULL; EVP_CIPHER_CTX cctx; EVP_CIPHER_CTX_init(&cctx); if (enclevel) outlen += PVK_SALTLEN; pklen = do_i2b(NULL, pk, 0); if (pklen < 0) return -1; outlen += pklen; p = malloc(outlen); if (!p) { PEMerror(ERR_R_MALLOC_FAILURE); return -1; } write_ledword(&p, MS_PVKMAGIC); write_ledword(&p, 0); if (pk->type == EVP_PKEY_DSA) write_ledword(&p, MS_KEYTYPE_SIGN); else write_ledword(&p, MS_KEYTYPE_KEYX); write_ledword(&p, enclevel ? 1 : 0); write_ledword(&p, enclevel ? PVK_SALTLEN : 0); write_ledword(&p, pklen); if (enclevel) { arc4random_buf(p, PVK_SALTLEN); salt = p; p += PVK_SALTLEN; } do_i2b(&p, pk, 0); if (enclevel == 0) { *out = p; return outlen; } else { char psbuf[PEM_BUFSIZE]; unsigned char keybuf[20]; int enctmplen, inlen; if (cb) inlen = cb(psbuf, PEM_BUFSIZE, 1, u); else inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 1, u); if (inlen <= 0) { PEMerror(PEM_R_BAD_PASSWORD_READ); goto error; } if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN, (unsigned char *)psbuf, inlen)) goto error; if (enclevel == 1) memset(keybuf + 5, 0, 11); p = salt + PVK_SALTLEN + 8; if (!EVP_EncryptInit_ex(&cctx, EVP_rc4(), NULL, keybuf, NULL)) goto error; explicit_bzero(keybuf, 20); if (!EVP_DecryptUpdate(&cctx, p, &enctmplen, p, pklen - 8)) goto error; if (!EVP_DecryptFinal_ex(&cctx, p + enctmplen, &enctmplen)) goto error; } EVP_CIPHER_CTX_cleanup(&cctx); *out = p; return outlen; error: EVP_CIPHER_CTX_cleanup(&cctx); free(p); return -1; }
static int i2b_PVK(unsigned char **out, EVP_PKEY *pk, int enclevel, pem_password_cb *cb, void *u) { int outlen = 24, pklen; unsigned char *p, *salt = NULL; EVP_CIPHER_CTX *cctx = EVP_CIPHER_CTX_new(); if (enclevel) outlen += PVK_SALTLEN; pklen = do_i2b(NULL, pk, 0); if (pklen < 0) return -1; outlen += pklen; if (!out) return outlen; if (*out) p = *out; else { p = OPENSSL_malloc(outlen); if (p == NULL) { PEMerr(PEM_F_I2B_PVK, ERR_R_MALLOC_FAILURE); return -1; } *out = p; } write_ledword(&p, MS_PVKMAGIC); write_ledword(&p, 0); if (EVP_PKEY_id(pk) == EVP_PKEY_DSA) write_ledword(&p, MS_KEYTYPE_SIGN); else write_ledword(&p, MS_KEYTYPE_KEYX); write_ledword(&p, enclevel ? 1 : 0); write_ledword(&p, enclevel ? PVK_SALTLEN : 0); write_ledword(&p, pklen); if (enclevel) { if (RAND_bytes(p, PVK_SALTLEN) <= 0) goto error; salt = p; p += PVK_SALTLEN; } do_i2b(&p, pk, 0); if (enclevel == 0) return outlen; else { char psbuf[PEM_BUFSIZE]; unsigned char keybuf[20]; int enctmplen, inlen; if (cb) inlen = cb(psbuf, PEM_BUFSIZE, 1, u); else inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 1, u); if (inlen <= 0) { PEMerr(PEM_F_I2B_PVK, PEM_R_BAD_PASSWORD_READ); goto error; } if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN, (unsigned char *)psbuf, inlen)) goto error; if (enclevel == 1) memset(keybuf + 5, 0, 11); p = salt + PVK_SALTLEN + 8; if (!EVP_EncryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL)) goto error; OPENSSL_cleanse(keybuf, 20); if (!EVP_DecryptUpdate(cctx, p, &enctmplen, p, pklen - 8)) goto error; if (!EVP_DecryptFinal_ex(cctx, p + enctmplen, &enctmplen)) goto error; } EVP_CIPHER_CTX_free(cctx); return outlen; error: EVP_CIPHER_CTX_free(cctx); return -1; }