static int do_i2b(unsigned char **out, EVP_PKEY *pk, int ispub) { unsigned char *p; unsigned int bitlen, magic = 0, keyalg; int outlen, noinc = 0; if (pk->type == EVP_PKEY_DSA) { bitlen = check_bitlen_dsa(pk->pkey.dsa, ispub, &magic); keyalg = MS_KEYALG_DSS_SIGN; } else if (pk->type == EVP_PKEY_RSA) { bitlen = check_bitlen_rsa(pk->pkey.rsa, ispub, &magic); keyalg = MS_KEYALG_RSA_KEYX; } else return -1; if (bitlen == 0) return -1; outlen = 16 + blob_length(bitlen, keyalg == MS_KEYALG_DSS_SIGN ? 1 : 0, ispub); if (out == NULL) return outlen; if (*out) p = *out; else { p = (unsigned char*)OPENSSL_malloc(outlen); if (!p) return -1; *out = p; noinc = 1; } if (ispub) *p++ = MS_PUBLICKEYBLOB; else *p++ = MS_PRIVATEKEYBLOB; *p++ = 0x2; *p++ = 0; *p++ = 0; write_ledword(&p, keyalg); write_ledword(&p, magic); write_ledword(&p, bitlen); if (keyalg == MS_KEYALG_DSS_SIGN) write_dsa(&p, pk->pkey.dsa, ispub); else write_rsa(&p, pk->pkey.rsa, ispub); if (!noinc) *out += outlen; return outlen; }
static int do_i2b(unsigned char **out, EVP_PKEY *pk, int ispub) { unsigned char *p; unsigned int bitlen, magic = 0, keyalg; int outlen, noinc = 0; int pktype = EVP_PKEY_id(pk); if (pktype == EVP_PKEY_DSA) { bitlen = check_bitlen_dsa(EVP_PKEY_get0_DSA(pk), ispub, &magic); keyalg = MS_KEYALG_DSS_SIGN; } else if (pktype == EVP_PKEY_RSA) { bitlen = check_bitlen_rsa(EVP_PKEY_get0_RSA(pk), ispub, &magic); keyalg = MS_KEYALG_RSA_KEYX; } else return -1; if (bitlen == 0) return -1; outlen = 16 + blob_length(bitlen, keyalg == MS_KEYALG_DSS_SIGN ? 1 : 0, ispub); if (out == NULL) return outlen; if (*out) p = *out; else { if ((p = OPENSSL_malloc(outlen)) == NULL) { PEMerr(PEM_F_DO_I2B, ERR_R_MALLOC_FAILURE); return -1; } *out = p; noinc = 1; } if (ispub) *p++ = MS_PUBLICKEYBLOB; else *p++ = MS_PRIVATEKEYBLOB; *p++ = 0x2; *p++ = 0; *p++ = 0; write_ledword(&p, keyalg); write_ledword(&p, magic); write_ledword(&p, bitlen); if (keyalg == MS_KEYALG_DSS_SIGN) write_dsa(&p, EVP_PKEY_get0_DSA(pk), ispub); else write_rsa(&p, EVP_PKEY_get0_RSA(pk), ispub); if (!noinc) *out += outlen; return outlen; }
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; }