diff options
Diffstat (limited to 'Cryptlib/OpenSSL/crypto/pem')
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_all.c | 220 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_err.c | 34 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_info.c | 35 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_lib.c | 143 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_pk8.c | 2 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_pkey.c | 152 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_seal.c | 6 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_x509.c | 1 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_xaux.c | 1 | ||||
| -rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pvkfmt.c | 883 |
10 files changed, 1290 insertions, 187 deletions
diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_all.c b/Cryptlib/OpenSSL/crypto/pem/pem_all.c index d4022aac..0e5be63e 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_all.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_all.c @@ -110,7 +110,6 @@ */ #include <stdio.h> -#undef SSLEAY_MACROS #include "cryptlib.h" #include <openssl/bio.h> #include <openssl/evp.h> @@ -194,16 +193,21 @@ int PEM_write_bio_RSAPrivateKey(BIO *bp, RSA *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - EVP_PKEY *k; - int ret; - k = EVP_PKEY_new(); - if (!k) - return 0; - EVP_PKEY_set1_RSA(k, x); - - ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u); - EVP_PKEY_free(k); - return ret; + if (FIPS_mode()) { + EVP_PKEY *k; + int ret; + k = EVP_PKEY_new(); + if (!k) + return 0; + EVP_PKEY_set1_RSA(k, x); + + ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u); + EVP_PKEY_free(k); + return ret; + } else + return PEM_ASN1_write_bio((i2d_of_void *)i2d_RSAPrivateKey, + PEM_STRING_RSA, bp, x, enc, kstr, klen, cb, + u); } # ifndef OPENSSL_NO_FP_API @@ -211,17 +215,21 @@ int PEM_write_RSAPrivateKey(FILE *fp, RSA *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - EVP_PKEY *k; - int ret; - k = EVP_PKEY_new(); - if (!k) - return 0; - - EVP_PKEY_set1_RSA(k, x); - - ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u); - EVP_PKEY_free(k); - return ret; + if (FIPS_mode()) { + EVP_PKEY *k; + int ret; + k = EVP_PKEY_new(); + if (!k) + return 0; + + EVP_PKEY_set1_RSA(k, x); + + ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u); + EVP_PKEY_free(k); + return ret; + } else + return PEM_ASN1_write((i2d_of_void *)i2d_RSAPrivateKey, + PEM_STRING_RSA, fp, x, enc, kstr, klen, cb, u); } # endif @@ -257,7 +265,7 @@ DSA *PEM_read_bio_DSAPrivateKey(BIO *bp, DSA **dsa, pem_password_cb *cb, { EVP_PKEY *pktmp; pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); - return pkey_get_dsa(pktmp, dsa); + return pkey_get_dsa(pktmp, dsa); /* will free pktmp */ } # ifdef OPENSSL_FIPS @@ -266,16 +274,21 @@ int PEM_write_bio_DSAPrivateKey(BIO *bp, DSA *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - EVP_PKEY *k; - int ret; - k = EVP_PKEY_new(); - if (!k) - return 0; - EVP_PKEY_set1_DSA(k, x); - - ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u); - EVP_PKEY_free(k); - return ret; + if (FIPS_mode()) { + EVP_PKEY *k; + int ret; + k = EVP_PKEY_new(); + if (!k) + return 0; + EVP_PKEY_set1_DSA(k, x); + + ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u); + EVP_PKEY_free(k); + return ret; + } else + return PEM_ASN1_write_bio((i2d_of_void *)i2d_DSAPrivateKey, + PEM_STRING_DSA, bp, x, enc, kstr, klen, cb, + u); } # ifndef OPENSSL_NO_FP_API @@ -283,15 +296,19 @@ int PEM_write_DSAPrivateKey(FILE *fp, DSA *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - EVP_PKEY *k; - int ret; - k = EVP_PKEY_new(); - if (!k) - return 0; - EVP_PKEY_set1_DSA(k, x); - ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u); - EVP_PKEY_free(k); - return ret; + if (FIPS_mode()) { + EVP_PKEY *k; + int ret; + k = EVP_PKEY_new(); + if (!k) + return 0; + EVP_PKEY_set1_DSA(k, x); + ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u); + EVP_PKEY_free(k); + return ret; + } else + return PEM_ASN1_write((i2d_of_void *)i2d_DSAPrivateKey, + PEM_STRING_DSA, fp, x, enc, kstr, klen, cb, u); } # endif @@ -306,7 +323,7 @@ DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **dsa, pem_password_cb *cb, void *u) { EVP_PKEY *pktmp; pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); - return pkey_get_dsa(pktmp, dsa); + return pkey_get_dsa(pktmp, dsa); /* will free pktmp */ } # endif @@ -335,7 +352,7 @@ EC_KEY *PEM_read_bio_ECPrivateKey(BIO *bp, EC_KEY **key, pem_password_cb *cb, { EVP_PKEY *pktmp; pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); - return pkey_get_eckey(pktmp, key); + return pkey_get_eckey(pktmp, key); /* will free pktmp */ } IMPLEMENT_PEM_rw_const(ECPKParameters, EC_GROUP, PEM_STRING_ECPARAMETERS, @@ -345,16 +362,21 @@ int PEM_write_bio_ECPrivateKey(BIO *bp, EC_KEY *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - EVP_PKEY *k; - int ret; - k = EVP_PKEY_new(); - if (!k) - return 0; - EVP_PKEY_set1_EC_KEY(k, x); - - ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u); - EVP_PKEY_free(k); - return ret; + if (FIPS_mode()) { + EVP_PKEY *k; + int ret; + k = EVP_PKEY_new(); + if (!k) + return 0; + EVP_PKEY_set1_EC_KEY(k, x); + + ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u); + EVP_PKEY_free(k); + return ret; + } else + return PEM_ASN1_write_bio((i2d_of_void *)i2d_ECPrivateKey, + PEM_STRING_ECPRIVATEKEY, + bp, x, enc, kstr, klen, cb, u); } # ifndef OPENSSL_NO_FP_API @@ -362,15 +384,20 @@ int PEM_write_ECPrivateKey(FILE *fp, EC_KEY *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { - EVP_PKEY *k; - int ret; - k = EVP_PKEY_new(); - if (!k) - return 0; - EVP_PKEY_set1_EC_KEY(k, x); - ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u); - EVP_PKEY_free(k); - return ret; + if (FIPS_mode()) { + EVP_PKEY *k; + int ret; + k = EVP_PKEY_new(); + if (!k) + return 0; + EVP_PKEY_set1_EC_KEY(k, x); + ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u); + EVP_PKEY_free(k); + return ret; + } else + return PEM_ASN1_write((i2d_of_void *)i2d_ECPrivateKey, + PEM_STRING_ECPRIVATEKEY, + fp, x, enc, kstr, klen, cb, u); } # endif @@ -385,7 +412,7 @@ EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb, { EVP_PKEY *pktmp; pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); - return pkey_get_eckey(pktmp, eckey); + return pkey_get_eckey(pktmp, eckey); /* will free pktmp */ } # endif @@ -394,66 +421,7 @@ EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb, #ifndef OPENSSL_NO_DH -IMPLEMENT_PEM_rw_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams) -#endif -/*- - * The PrivateKey case is not that straightforward. - * IMPLEMENT_PEM_rw_cb(PrivateKey, EVP_PKEY, PEM_STRING_EVP_PKEY, PrivateKey) - * does not work, RSA and DSA keys have specific strings. - * (When reading, parameter PEM_STRING_EVP_PKEY is a wildcard for anything - * appropriate.) - */ -#ifdef OPENSSL_FIPS -static const char *pkey_str(EVP_PKEY *x) -{ - switch (x->type) { - case EVP_PKEY_RSA: - return PEM_STRING_RSA; - - case EVP_PKEY_DSA: - return PEM_STRING_DSA; - - case EVP_PKEY_EC: - return PEM_STRING_ECPRIVATEKEY; - - default: - return NULL; - } -} - -int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, - unsigned char *kstr, int klen, - pem_password_cb *cb, void *u) -{ - if (FIPS_mode()) - return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, - (char *)kstr, klen, cb, u); - else - return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, - pkey_str(x), bp, (char *)x, enc, kstr, klen, - cb, u); -} - -# ifndef OPENSSL_NO_FP_API -int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, - unsigned char *kstr, int klen, - pem_password_cb *cb, void *u) -{ - if (FIPS_mode()) - return PEM_write_PKCS8PrivateKey(fp, x, enc, - (char *)kstr, klen, cb, u); - else - return PEM_ASN1_write((i2d_of_void *)i2d_PrivateKey, - pkey_str(x), fp, (char *)x, enc, kstr, klen, cb, - u); -} -# endif - -#else -IMPLEMENT_PEM_write_cb(PrivateKey, EVP_PKEY, - ((x->type == - EVP_PKEY_DSA) ? PEM_STRING_DSA : (x->type == - EVP_PKEY_RSA) ? - PEM_STRING_RSA : PEM_STRING_ECPRIVATEKEY), PrivateKey) +IMPLEMENT_PEM_write_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams) + IMPLEMENT_PEM_write_const(DHxparams, DH, PEM_STRING_DHXPARAMS, DHxparams) #endif - IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY) +IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY) diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_err.c b/Cryptlib/OpenSSL/crypto/pem/pem_err.c index 7452d25e..e1f4fdb4 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_err.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_err.c @@ -1,6 +1,6 @@ /* crypto/pem/pem_err.c */ /* ==================================================================== - * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2011 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -70,10 +70,22 @@ # define ERR_REASON(reason) ERR_PACK(ERR_LIB_PEM,0,reason) static ERR_STRING_DATA PEM_str_functs[] = { + {ERR_FUNC(PEM_F_B2I_DSS), "B2I_DSS"}, + {ERR_FUNC(PEM_F_B2I_PVK_BIO), "b2i_PVK_bio"}, + {ERR_FUNC(PEM_F_B2I_RSA), "B2I_RSA"}, + {ERR_FUNC(PEM_F_CHECK_BITLEN_DSA), "CHECK_BITLEN_DSA"}, + {ERR_FUNC(PEM_F_CHECK_BITLEN_RSA), "CHECK_BITLEN_RSA"}, {ERR_FUNC(PEM_F_D2I_PKCS8PRIVATEKEY_BIO), "d2i_PKCS8PrivateKey_bio"}, {ERR_FUNC(PEM_F_D2I_PKCS8PRIVATEKEY_FP), "d2i_PKCS8PrivateKey_fp"}, + {ERR_FUNC(PEM_F_DO_B2I), "DO_B2I"}, + {ERR_FUNC(PEM_F_DO_B2I_BIO), "DO_B2I_BIO"}, + {ERR_FUNC(PEM_F_DO_BLOB_HEADER), "DO_BLOB_HEADER"}, {ERR_FUNC(PEM_F_DO_PK8PKEY), "DO_PK8PKEY"}, {ERR_FUNC(PEM_F_DO_PK8PKEY_FP), "DO_PK8PKEY_FP"}, + {ERR_FUNC(PEM_F_DO_PVK_BODY), "DO_PVK_BODY"}, + {ERR_FUNC(PEM_F_DO_PVK_HEADER), "DO_PVK_HEADER"}, + {ERR_FUNC(PEM_F_I2B_PVK), "I2B_PVK"}, + {ERR_FUNC(PEM_F_I2B_PVK_BIO), "i2b_PVK_bio"}, {ERR_FUNC(PEM_F_LOAD_IV), "LOAD_IV"}, {ERR_FUNC(PEM_F_PEM_ASN1_READ), "PEM_ASN1_read"}, {ERR_FUNC(PEM_F_PEM_ASN1_READ_BIO), "PEM_ASN1_read_bio"}, @@ -87,13 +99,17 @@ static ERR_STRING_DATA PEM_str_functs[] = { {ERR_FUNC(PEM_F_PEM_PK8PKEY), "PEM_PK8PKEY"}, {ERR_FUNC(PEM_F_PEM_READ), "PEM_read"}, {ERR_FUNC(PEM_F_PEM_READ_BIO), "PEM_read_bio"}, + {ERR_FUNC(PEM_F_PEM_READ_BIO_DHPARAMS), "PEM_READ_BIO_DHPARAMS"}, + {ERR_FUNC(PEM_F_PEM_READ_BIO_PARAMETERS), "PEM_read_bio_Parameters"}, {ERR_FUNC(PEM_F_PEM_READ_BIO_PRIVATEKEY), "PEM_READ_BIO_PRIVATEKEY"}, + {ERR_FUNC(PEM_F_PEM_READ_DHPARAMS), "PEM_READ_DHPARAMS"}, {ERR_FUNC(PEM_F_PEM_READ_PRIVATEKEY), "PEM_READ_PRIVATEKEY"}, {ERR_FUNC(PEM_F_PEM_SEALFINAL), "PEM_SealFinal"}, {ERR_FUNC(PEM_F_PEM_SEALINIT), "PEM_SealInit"}, {ERR_FUNC(PEM_F_PEM_SIGNFINAL), "PEM_SignFinal"}, {ERR_FUNC(PEM_F_PEM_WRITE), "PEM_write"}, {ERR_FUNC(PEM_F_PEM_WRITE_BIO), "PEM_write_bio"}, + {ERR_FUNC(PEM_F_PEM_WRITE_PRIVATEKEY), "PEM_WRITE_PRIVATEKEY"}, {ERR_FUNC(PEM_F_PEM_X509_INFO_READ), "PEM_X509_INFO_read"}, {ERR_FUNC(PEM_F_PEM_X509_INFO_READ_BIO), "PEM_X509_INFO_read_bio"}, {ERR_FUNC(PEM_F_PEM_X509_INFO_WRITE_BIO), "PEM_X509_INFO_write_bio"}, @@ -105,9 +121,21 @@ static ERR_STRING_DATA PEM_str_reasons[] = { {ERR_REASON(PEM_R_BAD_DECRYPT), "bad decrypt"}, {ERR_REASON(PEM_R_BAD_END_LINE), "bad end line"}, {ERR_REASON(PEM_R_BAD_IV_CHARS), "bad iv chars"}, + {ERR_REASON(PEM_R_BAD_MAGIC_NUMBER), "bad magic number"}, {ERR_REASON(PEM_R_BAD_PASSWORD_READ), "bad password read"}, + {ERR_REASON(PEM_R_BAD_VERSION_NUMBER), "bad version number"}, + {ERR_REASON(PEM_R_BIO_WRITE_FAILURE), "bio write failure"}, + {ERR_REASON(PEM_R_CIPHER_IS_NULL), "cipher is null"}, {ERR_REASON(PEM_R_ERROR_CONVERTING_PRIVATE_KEY), "error converting private key"}, + {ERR_REASON(PEM_R_EXPECTING_PRIVATE_KEY_BLOB), + "expecting private key blob"}, + {ERR_REASON(PEM_R_EXPECTING_PUBLIC_KEY_BLOB), + "expecting public key blob"}, + {ERR_REASON(PEM_R_INCONSISTENT_HEADER), "inconsistent header"}, + {ERR_REASON(PEM_R_KEYBLOB_HEADER_PARSE_ERROR), + "keyblob header parse error"}, + {ERR_REASON(PEM_R_KEYBLOB_TOO_SHORT), "keyblob too short"}, {ERR_REASON(PEM_R_NOT_DEK_INFO), "not dek info"}, {ERR_REASON(PEM_R_NOT_ENCRYPTED), "not encrypted"}, {ERR_REASON(PEM_R_NOT_PROC_TYPE), "not proc type"}, @@ -115,10 +143,14 @@ static ERR_STRING_DATA PEM_str_reasons[] = { {ERR_REASON(PEM_R_PROBLEMS_GETTING_PASSWORD), "problems getting password"}, {ERR_REASON(PEM_R_PUBLIC_KEY_NO_RSA), "public key no rsa"}, + {ERR_REASON(PEM_R_PVK_DATA_TOO_SHORT), "pvk data too short"}, + {ERR_REASON(PEM_R_PVK_TOO_SHORT), "pvk too short"}, {ERR_REASON(PEM_R_READ_KEY), "read key"}, {ERR_REASON(PEM_R_SHORT_HEADER), "short header"}, {ERR_REASON(PEM_R_UNSUPPORTED_CIPHER), "unsupported cipher"}, {ERR_REASON(PEM_R_UNSUPPORTED_ENCRYPTION), "unsupported encryption"}, + {ERR_REASON(PEM_R_UNSUPPORTED_KEY_COMPONENTS), + "unsupported key components"}, {0, NULL} }; diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_info.c b/Cryptlib/OpenSSL/crypto/pem/pem_info.c index 91842b6c..68747d16 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_info.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_info.c @@ -99,8 +99,8 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, long len, error = 0; int ok = 0; STACK_OF(X509_INFO) *ret = NULL; - unsigned int i, raw; - d2i_of_void *d2i; + unsigned int i, raw, ptype; + d2i_of_void *d2i = 0; if (sk == NULL) { if ((ret = sk_X509_INFO_new_null()) == NULL) { @@ -114,6 +114,7 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, goto err; for (;;) { raw = 0; + ptype = 0; i = PEM_read_bio(bp, &name, &header, &data, &len); if (i == 0) { error = ERR_GET_REASON(ERR_peek_last_error()); @@ -171,10 +172,8 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, xi->enc_len = 0; xi->x_pkey = X509_PKEY_new(); - if ((xi->x_pkey->dec_pkey = EVP_PKEY_new()) == NULL) - goto err; - xi->x_pkey->dec_pkey->type = EVP_PKEY_RSA; - pp = &(xi->x_pkey->dec_pkey->pkey.rsa); + ptype = EVP_PKEY_RSA; + pp = &xi->x_pkey->dec_pkey; if ((int)strlen(header) > 10) /* assume encrypted */ raw = 1; } else @@ -194,10 +193,8 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, xi->enc_len = 0; xi->x_pkey = X509_PKEY_new(); - if ((xi->x_pkey->dec_pkey = EVP_PKEY_new()) == NULL) - goto err; - xi->x_pkey->dec_pkey->type = EVP_PKEY_DSA; - pp = &xi->x_pkey->dec_pkey->pkey.dsa; + ptype = EVP_PKEY_DSA; + pp = &xi->x_pkey->dec_pkey; if ((int)strlen(header) > 10) /* assume encrypted */ raw = 1; } else @@ -217,10 +214,8 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, xi->enc_len = 0; xi->x_pkey = X509_PKEY_new(); - if ((xi->x_pkey->dec_pkey = EVP_PKEY_new()) == NULL) - goto err; - xi->x_pkey->dec_pkey->type = EVP_PKEY_EC; - pp = &(xi->x_pkey->dec_pkey->pkey.ec); + ptype = EVP_PKEY_EC; + pp = &xi->x_pkey->dec_pkey; if ((int)strlen(header) > 10) /* assume encrypted */ raw = 1; } else @@ -239,7 +234,12 @@ STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, if (!PEM_do_header(&cipher, data, &len, cb, u)) goto err; p = data; - if (d2i(pp, &p, len) == NULL) { + if (ptype) { + if (!d2i_PrivateKey(ptype, pp, &p, len)) { + PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_ASN1_LIB); + goto err; + } + } else if (d2i(pp, &p, len) == NULL) { PEMerr(PEM_F_PEM_X509_INFO_READ_BIO, ERR_R_ASN1_LIB); goto err; } @@ -324,6 +324,11 @@ int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc, */ if (xi->x_pkey != NULL) { if ((xi->enc_data != NULL) && (xi->enc_len > 0)) { + if (enc == NULL) { + PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO, PEM_R_CIPHER_IS_NULL); + goto err; + } + /* copy from weirdo names into more normal things */ iv = xi->enc_cipher.iv; data = (unsigned char *)xi->enc_data; diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_lib.c b/Cryptlib/OpenSSL/crypto/pem/pem_lib.c index 8febf104..a29821aa 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_lib.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_lib.c @@ -57,6 +57,7 @@ */ #include <stdio.h> +#include <ctype.h> #include "cryptlib.h" #include <openssl/buffer.h> #include <openssl/objects.h> @@ -65,9 +66,13 @@ #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/pkcs12.h> +#include "asn1_locl.h" #ifndef OPENSSL_NO_DES # include <openssl/des.h> #endif +#ifndef OPENSSL_NO_ENGINE +# include <openssl/engine.h> +#endif const char PEM_version[] = "PEM" OPENSSL_VERSION_PTEXT; @@ -75,6 +80,7 @@ const char PEM_version[] = "PEM" OPENSSL_VERSION_PTEXT; static int load_iv(char **fromp, unsigned char *to, int num); static int check_pem(const char *nm, const char *name); +int pem_check_suffix(const char *pem_str, const char *suffix); int PEM_def_callback(char *buf, int num, int w, void *key) { @@ -99,7 +105,7 @@ int PEM_def_callback(char *buf, int num, int w, void *key) prompt = "Enter PEM pass phrase:"; for (;;) { - i = EVP_read_pw_string(buf, num, prompt, w); + i = EVP_read_pw_string_min(buf, MIN_LENGTH, num, prompt, w); if (i != 0) { PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)num); @@ -181,22 +187,53 @@ static int check_pem(const char *nm, const char *name) /* Make PEM_STRING_EVP_PKEY match any private key */ - if (!strcmp(nm, PEM_STRING_PKCS8) && !strcmp(name, PEM_STRING_EVP_PKEY)) - return 1; - - if (!strcmp(nm, PEM_STRING_PKCS8INF) && - !strcmp(name, PEM_STRING_EVP_PKEY)) - return 1; - - if (!strcmp(nm, PEM_STRING_RSA) && !strcmp(name, PEM_STRING_EVP_PKEY)) - return 1; - - if (!strcmp(nm, PEM_STRING_DSA) && !strcmp(name, PEM_STRING_EVP_PKEY)) + if (!strcmp(name, PEM_STRING_EVP_PKEY)) { + int slen; + const EVP_PKEY_ASN1_METHOD *ameth; + if (!strcmp(nm, PEM_STRING_PKCS8)) + return 1; + if (!strcmp(nm, PEM_STRING_PKCS8INF)) + return 1; + slen = pem_check_suffix(nm, "PRIVATE KEY"); + if (slen > 0) { + /* + * NB: ENGINE implementations wont contain a deprecated old + * private key decode function so don't look for them. + */ + ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); + if (ameth && ameth->old_priv_decode) + return 1; + } + return 0; + } + + if (!strcmp(name, PEM_STRING_PARAMETERS)) { + int slen; + const EVP_PKEY_ASN1_METHOD *ameth; + slen = pem_check_suffix(nm, "PARAMETERS"); + if (slen > 0) { + ENGINE *e; + ameth = EVP_PKEY_asn1_find_str(&e, nm, slen); + if (ameth) { + int r; + if (ameth->param_decode) + r = 1; + else + r = 0; +#ifndef OPENSSL_NO_ENGINE + if (e) + ENGINE_finish(e); +#endif + return r; + } + } + return 0; + } + /* If reading DH parameters handle X9.42 DH format too */ + if (!strcmp(nm, PEM_STRING_DHXPARAMS) && + !strcmp(name, PEM_STRING_DHPARAMS)) return 1; - if (!strcmp(nm, PEM_STRING_ECPRIVATEKEY) && - !strcmp(name, PEM_STRING_EVP_PKEY)) - return 1; /* Permit older strings */ if (!strcmp(nm, PEM_STRING_X509_OLD) && !strcmp(name, PEM_STRING_X509)) @@ -223,6 +260,14 @@ static int check_pem(const char *nm, const char *name) !strcmp(name, PEM_STRING_PKCS7)) return 1; +#ifndef OPENSSL_NO_CMS + if (!strcmp(nm, PEM_STRING_X509) && !strcmp(name, PEM_STRING_CMS)) + return 1; + /* Allow CMS to be read from PKCS#7 headers */ + if (!strcmp(nm, PEM_STRING_PKCS7) && !strcmp(name, PEM_STRING_CMS)) + return 1; +#endif + return 0; } @@ -272,7 +317,7 @@ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, #ifndef OPENSSL_NO_FP_API int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp, - char *x, const EVP_CIPHER *enc, unsigned char *kstr, + void *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *callback, void *u) { BIO *b; @@ -290,7 +335,7 @@ int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp, #endif int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, - char *x, const EVP_CIPHER *enc, unsigned char *kstr, + void *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *callback, void *u) { EVP_CIPHER_CTX ctx; @@ -348,7 +393,8 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, * The 'iv' is used as the iv and as a salt. It is NOT taken from * the BytesToKey function */ - EVP_BytesToKey(enc, EVP_md5(), iv, kstr, klen, 1, key, NULL); + if (!EVP_BytesToKey(enc, EVP_md5(), iv, kstr, klen, 1, key, NULL)) + goto err; if (kstr == (unsigned char *)buf) OPENSSL_cleanse(buf, PEM_BUFSIZE); @@ -362,12 +408,15 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, /* k=strlen(buf); */ EVP_CIPHER_CTX_init(&ctx); - EVP_EncryptInit_ex(&ctx, enc, NULL, key, iv); - EVP_EncryptUpdate(&ctx, data, &j, data, i); - EVP_EncryptFinal_ex(&ctx, &(data[j]), &i); + ret = 1; + if (!EVP_EncryptInit_ex(&ctx, enc, NULL, key, iv) + || !EVP_EncryptUpdate(&ctx, data, &j, data, i) + || !EVP_EncryptFinal_ex(&ctx, &(data[j]), &i)) + ret = 0; EVP_CIPHER_CTX_cleanup(&ctx); + if (ret == 0) + goto err; i += j; - ret = 1; } else { ret = 1; buf[0] = '\0'; @@ -390,7 +439,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, pem_password_cb *callback, void *u) { - int i, j, o, klen; + int i = 0, j, o, klen; long len; EVP_CIPHER_CTX ctx; unsigned char key[EVP_MAX_KEY_LENGTH]; @@ -413,19 +462,23 @@ int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, ebcdic2ascii(buf, buf, klen); #endif - EVP_BytesToKey(cipher->cipher, EVP_md5(), &(cipher->iv[0]), - (unsigned char *)buf, klen, 1, key, NULL); + if (!EVP_BytesToKey(cipher->cipher, EVP_md5(), &(cipher->iv[0]), + (unsigned char *)buf, klen, 1, key, NULL)) + return 0; j = (int)len; EVP_CIPHER_CTX_init(&ctx); - EVP_DecryptInit_ex(&ctx, cipher->cipher, NULL, key, &(cipher->iv[0])); - EVP_DecryptUpdate(&ctx, data, &i, data, j); - o = EVP_DecryptFinal_ex(&ctx, &(data[i]), &j); + o = EVP_DecryptInit_ex(&ctx, cipher->cipher, NULL, key, &(cipher->iv[0])); + if (o) + o = EVP_DecryptUpdate(&ctx, data, &i, data, j); + if (o) + o = EVP_DecryptFinal_ex(&ctx, &(data[i]), &j); EVP_CIPHER_CTX_cleanup(&ctx); OPENSSL_cleanse((char *)buf, sizeof(buf)); OPENSSL_cleanse((char *)key, sizeof(key)); - j += i; - if (!o) { + if (o) + j += i; + else { PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT); return (0); } @@ -526,8 +579,8 @@ static int load_iv(char **fromp, unsigned char *to, int num) } #ifndef OPENSSL_NO_FP_API -int PEM_write(FILE *fp, char *name, char *header, unsigned char *data, - long len) +int PEM_write(FILE *fp, const char *name, const char *header, + const unsigned char *data, long len) { BIO *b; int ret; @@ -543,8 +596,8 @@ int PEM_write(FILE *fp, char *name, char *header, unsigned char *data, } #endif -int PEM_write_bio(BIO *bp, const char *name, char *header, - unsigned char *data, long len) +int PEM_write_bio(BIO *bp, const char *name, const char *header, + const unsigned char *data, long len) { int nlen, n, i, j, outl; unsigned char *buf = NULL; @@ -788,3 +841,25 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, BUF_MEM_free(dataB); return (0); } + +/* + * Check pem string and return prefix length. If for example the pem_str == + * "RSA PRIVATE KEY" and suffix = "PRIVATE KEY" the return value is 3 for the + * string "RSA". + */ + +int pem_check_suffix(const char *pem_str, const char *suffix) +{ + int pem_len = strlen(pem_str); + int suffix_len = strlen(suffix); + const char *p; + if (suffix_len + 1 >= pem_len) + return 0; + p = pem_str + pem_len - suffix_len; + if (strcmp(p, suffix)) + return 0; + p--; + if (*p != ' ') + return 0; + return p - pem_str; +} diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_pk8.c b/Cryptlib/OpenSSL/crypto/pem/pem_pk8.c index b98c76c4..5747c736 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_pk8.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_pk8.c @@ -138,6 +138,8 @@ static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid, if (kstr == buf) OPENSSL_cleanse(buf, klen); PKCS8_PRIV_KEY_INFO_free(p8inf); + if (p8 == NULL) + return 0; if (isder) ret = i2d_PKCS8_bio(bp, p8); else diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_pkey.c b/Cryptlib/OpenSSL/crypto/pem/pem_pkey.c index 5f5c4fe1..04d6319a 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_pkey.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_pkey.c @@ -65,6 +65,15 @@ #include <openssl/x509.h> #include <openssl/pkcs12.h> #include <openssl/pem.h> +#ifndef OPENSSL_NO_ENGINE +# include <openssl/engine.h> +#endif +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif +#include "asn1_locl.h" + +int pem_check_suffix(const char *pem_str, const char *suffix); EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u) @@ -73,19 +82,14 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, const unsigned char *p = NULL; unsigned char *data = NULL; long len; + int slen; EVP_PKEY *ret = NULL; if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u)) return NULL; p = data; - if (strcmp(nm, PEM_STRING_RSA) == 0) - ret = d2i_PrivateKey(EVP_PKEY_RSA, x, &p, len); - else if (strcmp(nm, PEM_STRING_DSA) == 0) - ret = d2i_PrivateKey(EVP_PKEY_DSA, x, &p, len); - else if (strcmp(nm, PEM_STRING_ECPRIVATEKEY) == 0) - ret = d2i_PrivateKey(EVP_PKEY_EC, x, &p, len); - else if (strcmp(nm, PEM_STRING_PKCS8INF) == 0) { + if (strcmp(nm, PEM_STRING_PKCS8INF) == 0) { PKCS8_PRIV_KEY_INFO *p8inf; p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len); if (!p8inf) @@ -125,6 +129,12 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, *x = ret; } PKCS8_PRIV_KEY_INFO_free(p8inf); + } else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0) { + const EVP_PKEY_ASN1_METHOD *ameth; + ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); + if (!ameth || !ameth->old_priv_decode) + goto p8err; + ret = d2i_PrivateKey(ameth->pkey_id, x, &p, len); } p8err: if (ret == NULL) @@ -136,6 +146,70 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, return (ret); } +int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + char pem_str[80]; + if (!x->ameth || x->ameth->priv_encode) + return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, + (char *)kstr, klen, cb, u); + + BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); + return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, + pem_str, bp, x, enc, kstr, klen, cb, u); +} + +EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x) +{ + char *nm = NULL; + const unsigned char *p = NULL; + unsigned char *data = NULL; + long len; + int slen; + EVP_PKEY *ret = NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_PARAMETERS, + bp, 0, NULL)) + return NULL; + p = data; + + if ((slen = pem_check_suffix(nm, "PARAMETERS")) > 0) { + ret = EVP_PKEY_new(); + if (!ret) + goto err; + if (!EVP_PKEY_set_type_str(ret, nm, slen) + || !ret->ameth->param_decode + || !ret->ameth->param_decode(ret, &p, len)) { + EVP_PKEY_free(ret); + ret = NULL; + goto err; + } + if (x) { + if (*x) + EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } + } + err: + if (ret == NULL) + PEMerr(PEM_F_PEM_READ_BIO_PARAMETERS, ERR_R_ASN1_LIB); + OPENSSL_free(nm); + OPENSSL_free(data); + return (ret); +} + +int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x) +{ + char pem_str[80]; + if (!x->ameth || !x->ameth->param_encode) + return 0; + + BIO_snprintf(pem_str, 80, "%s PARAMETERS", x->ameth->pem_str); + return PEM_ASN1_write_bio((i2d_of_void *)x->ameth->param_encode, + pem_str, bp, x, NULL, NULL, 0, 0, NULL); +} + #ifndef OPENSSL_NO_FP_API EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) @@ -152,4 +226,68 @@ EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, BIO_free(b); return (ret); } + +int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + BIO *b; + int ret; + + if ((b = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { + PEMerr(PEM_F_PEM_WRITE_PRIVATEKEY, ERR_R_BUF_LIB); + return 0; + } + ret = PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u); + BIO_free(b); + return ret; +} + +#endif + +#ifndef OPENSSL_NO_DH + +/* Transparently read in PKCS#3 or X9.42 DH parameters */ + +DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u) +{ + char *nm = NULL; + const unsigned char *p = NULL; + unsigned char *data = NULL; + long len; + DH *ret = NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_DHPARAMS, bp, cb, u)) + return NULL; + p = data; + + if (!strcmp(nm, PEM_STRING_DHXPARAMS)) + ret = d2i_DHxparams(x, &p, len); + else + ret = d2i_DHparams(x, &p, len); + + if (ret == NULL) + PEMerr(PEM_F_PEM_READ_BIO_DHPARAMS, ERR_R_ASN1_LIB); + OPENSSL_free(nm); + OPENSSL_free(data); + return ret; +} + +# ifndef OPENSSL_NO_FP_API +DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u) +{ + BIO *b; + DH *ret; + + if ((b = BIO_new(BIO_s_file())) == NULL) { + PEMerr(PEM_F_PEM_READ_DHPARAMS, ERR_R_BUF_LIB); + return (0); + } + BIO_set_fp(b, fp, BIO_NOCLOSE); + ret = PEM_read_bio_DHparams(b, x, cb, u); + BIO_free(b); + return (ret); +} +# endif + #endif diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_seal.c b/Cryptlib/OpenSSL/crypto/pem/pem_seal.c index a4a556a7..a5c18125 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_seal.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_seal.c @@ -94,7 +94,8 @@ int PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type, EVP_MD *md_type, EVP_EncodeInit(&ctx->encode); EVP_MD_CTX_init(&ctx->md); - EVP_SignInit(&ctx->md, md_type); + if (!EVP_SignInit(&ctx->md, md_type)) + goto err; EVP_CIPHER_CTX_init(&ctx->cipher); ret = EVP_SealInit(&ctx->cipher, type, ek, ekl, iv, pubk, npubk); @@ -161,7 +162,8 @@ int PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig, int *sigl, goto err; } - EVP_EncryptFinal_ex(&ctx->cipher, s, (int *)&i); + if (!EVP_EncryptFinal_ex(&ctx->cipher, s, (int *)&i)) + goto err; EVP_EncodeUpdate(&ctx->encode, out, &j, s, i); *outl = j; out += j; diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_x509.c b/Cryptlib/OpenSSL/crypto/pem/pem_x509.c index 9d75d206..3c20ff28 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_x509.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_x509.c @@ -58,7 +58,6 @@ */ #include <stdio.h> -#undef SSLEAY_MACROS #include "cryptlib.h" #include <openssl/bio.h> #include <openssl/evp.h> diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_xaux.c b/Cryptlib/OpenSSL/crypto/pem/pem_xaux.c index ebd1803d..c5234301 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_xaux.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_xaux.c @@ -58,7 +58,6 @@ */ #include <stdio.h> -#undef SSLEAY_MACROS #include "cryptlib.h" #include <openssl/bio.h> #include <openssl/evp.h> diff --git a/Cryptlib/OpenSSL/crypto/pem/pvkfmt.c b/Cryptlib/OpenSSL/crypto/pem/pvkfmt.c new file mode 100644 index 00000000..ee4b6a82 --- /dev/null +++ b/Cryptlib/OpenSSL/crypto/pem/pvkfmt.c @@ -0,0 +1,883 @@ +/* + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project + * 2005. + */ +/* ==================================================================== + * Copyright (c) 2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* + * Support for PVK format keys and related structures (such a PUBLICKEYBLOB + * and PRIVATEKEYBLOB). + */ + +#include "cryptlib.h" +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/bn.h> +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) +# include <openssl/dsa.h> +# include <openssl/rsa.h> + +/* + * Utility function: read a DWORD (4 byte unsigned integer) in little endian + * format + */ + +static unsigned int read_ledword(const unsigned char **in) +{ + const unsigned char *p = *in; + unsigned int ret; + ret = *p++; + ret |= (*p++ << 8); + ret |= (*p++ << 16); + ret |= (*p++ << 24); + *in = p; + return ret; +} + +/* + * Read a BIGNUM in little endian format. The docs say that this should take + * up bitlen/8 bytes. + */ + +static int read_lebn(const unsigned char **in, unsigned int nbyte, BIGNUM **r) +{ + const unsigned char *p; + unsigned char *tmpbuf, *q; + unsigned int i; + p = *in + nbyte - 1; + tmpbuf = OPENSSL_malloc(nbyte); + if (!tmpbuf) + return 0; + q = tmpbuf; + for (i = 0; i < nbyte; i++) + *q++ = *p--; + *r = BN_bin2bn(tmpbuf, nbyte, NULL); + OPENSSL_free(tmpbuf); + if (*r) { + *in += nbyte; + return 1; + } else + return 0; +} + +/* Convert private key blob to EVP_PKEY: RSA and DSA keys supported */ + +# define MS_PUBLICKEYBLOB 0x6 +# define MS_PRIVATEKEYBLOB 0x7 +# define MS_RSA1MAGIC 0x31415352L +# define MS_RSA2MAGIC 0x32415352L +# define MS_DSS1MAGIC 0x31535344L +# define MS_DSS2MAGIC 0x32535344L + +# define MS_KEYALG_RSA_KEYX 0xa400 +# define MS_KEYALG_DSS_SIGN 0x2200 + +# define MS_KEYTYPE_KEYX 0x1 +# define MS_KEYTYPE_SIGN 0x2 + +/* The PVK file magic number: seems to spell out "bobsfile", who is Bob? */ +# define MS_PVKMAGIC 0xb0b5f11eL +/* Salt length for PVK files */ +# define PVK_SALTLEN 0x10 + +static EVP_PKEY *b2i_rsa(const unsigned char **in, unsigned int length, + unsigned int bitlen, int ispub); +static EVP_PKEY *b2i_dss(const unsigned char **in, unsigned int length, + unsigned int bitlen, int ispub); + +static int do_blob_header(const unsigned char **in, unsigned int length, + unsigned int *pmagic, unsigned int *pbitlen, + int *pisdss, int *pispub) +{ + const unsigned char *p = *in; + if (length < 16) + return 0; + /* bType */ + if (*p == MS_PUBLICKEYBLOB) { + if (*pispub == 0) { + PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB); + return 0; + } + *pispub = 1; + } else if (*p == MS_PRIVATEKEYBLOB) { + if (*pispub == 1) { + PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB); + return 0; + } + *pispub = 0; + } else + return 0; + p++; + /* Version */ + if (*p++ != 0x2) { + PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_VERSION_NUMBER); + return 0; + } + /* Ignore reserved, aiKeyAlg */ + p += 6; + *pmagic = read_ledword(&p); + *pbitlen = read_ledword(&p); + *pisdss = 0; + switch (*pmagic) { + + case MS_DSS1MAGIC: + *pisdss = 1; + case MS_RSA1MAGIC: + if (*pispub == 0) { + PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PRIVATE_KEY_BLOB); + return 0; + } + break; + + case MS_DSS2MAGIC: + *pisdss = 1; + case MS_RSA2MAGIC: + if (*pispub == 1) { + PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_EXPECTING_PUBLIC_KEY_BLOB); + return 0; + } + break; + + default: + PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_MAGIC_NUMBER); + return -1; + } + *in = p; + return 1; +} + +static unsigned int blob_length(unsigned bitlen, int isdss, int ispub) +{ + unsigned int nbyte, hnbyte; + nbyte = (bitlen + 7) >> 3; + hnbyte = (bitlen + 15) >> 4; + if (isdss) { + + /* + * Expected length: 20 for q + 3 components bitlen each + 24 for seed + * structure. + */ + if (ispub) + return 44 + 3 * nbyte; + /* + * Expected length: 20 for q, priv, 2 bitlen components + 24 for seed + * structure. + */ + else + return 64 + 2 * nbyte; + } else { + /* Expected length: 4 for 'e' + 'n' */ + if (ispub) + return 4 + nbyte; + else + /* + * Expected length: 4 for 'e' and 7 other components. 2 + * components are bitlen size, 5 are bitlen/2 + */ + return 4 + 2 * nbyte + 5 * hnbyte; + } + +} + +static EVP_PKEY *do_b2i(const unsigned char **in, unsigned int length, + int ispub) +{ + const unsigned char *p = *in; + unsigned int bitlen, magic; + int isdss; + if (do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) { + PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_HEADER_PARSE_ERROR); + return NULL; + } + length -= 16; + if (length < blob_length(bitlen, isdss, ispub)) { + PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_TOO_SHORT); + return NULL; + } + if (isdss) + return b2i_dss(&p, length, bitlen, ispub); + else + return b2i_rsa(&p, length, bitlen, ispub); +} + +static EVP_PKEY *do_b2i_bio(BIO *in, int ispub) +{ + const unsigned char *p; + unsigned char hdr_buf[16], *buf = NULL; + unsigned int bitlen, magic, length; + int isdss; + EVP_PKEY *ret = NULL; + if (BIO_read(in, hdr_buf, 16) != 16) { + PEMerr(PEM_F_DO_B2I_BIO, PEM_R_KEYBLOB_TOO_SHORT); + return NULL; + } + p = hdr_buf; + if (do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0) + return NULL; + + length = blob_length(bitlen, isdss, ispub); + buf = OPENSSL_malloc(length); + if (!buf) { + PEMerr(PEM_F_DO_B2I_BIO, ERR_R_MALLOC_FAILURE); + goto err; + } + p = buf; + if (BIO_read(in, buf, length) != (int)length) { + PEMerr(PEM_F_DO_B2I_BIO, PEM_R_KEYBLOB_TOO_SHORT); + goto err; + } + + if (isdss) + ret = b2i_dss(&p, length, bitlen, ispub); + else + ret = b2i_rsa(&p, length, bitlen, ispub); + + err: + if (buf) + OPENSSL_free(buf); + return ret; +} + +static EVP_PKEY *b2i_dss(const unsigned char **in, unsigned int length, + unsigned int bitlen, int ispub) +{ + const unsigned char *p = *in; + EVP_PKEY *ret = NULL; + DSA *dsa = NULL; + BN_CTX *ctx = NULL; + unsigned int nbyte; + nbyte = (bitlen + 7) >> 3; + + dsa = DSA_new(); + ret = EVP_PKEY_new(); + if (!dsa || !ret) + goto memerr; + if (!read_lebn(&p, nbyte, &dsa->p)) + goto memerr; + if (!read_lebn(&p, 20, &dsa->q)) + goto memerr; + if (!read_lebn(&p, nbyte, &dsa->g)) + goto memerr; + if (ispub) { + if (!read_lebn(&p, nbyte, &dsa->pub_key)) + goto memerr; + } else { + if (!read_lebn(&p, 20, &dsa->priv_key)) + goto memerr; + /* Calculate public key */ + if (!(dsa->pub_key = BN_new())) + goto memerr; + if (!(ctx = BN_CTX_new())) + goto memerr; + + if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) + + goto memerr; + BN_CTX_free(ctx); + } + + EVP_PKEY_set1_DSA(ret, dsa); + DSA_free(dsa); + *in = p; + return ret; + + memerr: + PEMerr(PEM_F_B2I_DSS, ERR_R_MALLOC_FAILURE); + if (dsa) + DSA_free(dsa); + if (ret) + EVP_PKEY_free(ret); + if (ctx) + BN_CTX_free(ctx); + return NULL; +} + +static EVP_PKEY *b2i_rsa(const unsigned char **in, unsigned int length, + unsigned int bitlen, int ispub) +{ + const unsigned char *p = *in; + EVP_PKEY *ret = NULL; + RSA *rsa = NULL; + unsigned int nbyte, hnbyte; + nbyte = (bitlen + 7) >> 3; + hnbyte = (bitlen + 15) >> 4; + rsa = RSA_new(); + ret = EVP_PKEY_new(); + if (!rsa || !ret) + goto memerr; + rsa->e = BN_new(); + if (!rsa->e) + goto memerr; + if (!BN_set_word(rsa->e, read_ledword(&p))) + goto memerr; + if (!read_lebn(&p, nbyte, &rsa->n)) + goto memerr; + if (!ispub) { + if (!read_lebn(&p, hnbyte, &rsa->p)) + goto memerr; + if (!read_lebn(&p, hnbyte, &rsa->q)) + goto memerr; + if (!read_lebn(&p, hnbyte, &rsa->dmp1)) + goto memerr; + if (!read_lebn(&p, hnbyte, &rsa->dmq1)) + goto memerr; + if (!read_lebn(&p, hnbyte, &rsa->iqmp)) + goto memerr; + if (!read_lebn(&p, nbyte, &rsa->d)) + goto memerr; + } + + EVP_PKEY_set1_RSA(ret, rsa); + RSA_free(rsa); + *in = p; + return ret; + memerr: + PEMerr(PEM_F_B2I_RSA, ERR_R_MALLOC_FAILURE); + if (rsa) + RSA_free(rsa); + if (ret) + EVP_PKEY_free(ret); + return NULL; +} + +EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length) +{ + return do_b2i(in, length, 0); +} + +EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length) +{ + return do_b2i(in, length, 1); +} + +EVP_PKEY *b2i_PrivateKey_bio(BIO *in) +{ + return do_b2i_bio(in, 0); +} + +EVP_PKEY *b2i_PublicKey_bio(BIO *in) +{ + return do_b2i_bio(in, 1); +} + +static void write_ledword(unsigned char **out, unsigned int dw) +{ + unsigned char *p = *out; + *p++ = dw & 0xff; + *p++ = (dw >> 8) & 0xff; + *p++ = (dw >> 16) & 0xff; + *p++ = (dw >> 24) & 0xff; + *out = p; +} + +static void write_lebn(unsigned char **out, const BIGNUM *bn, int len) +{ + int nb, i; + unsigned char *p = *out, *q, c; + nb = BN_num_bytes(bn); + BN_bn2bin(bn, p); + q = p + nb - 1; + /* In place byte order reversal */ + for (i = 0; i < nb / 2; i++) { + c = *p; + *p++ = *q; + *q-- = c; + } + *out += nb; + /* Pad with zeroes if we have to */ + if (len > 0) { + len -= nb; + if (len > 0) { + memset(*out, 0, len); + *out += len; + } + } +} + +static int check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *magic); +static int check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *magic); + +static void write_rsa(unsigned char **out, RSA *rsa, int ispub); +static void write_dsa(unsigned char **out, DSA *dsa, int ispub); + +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 = 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_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 check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *pmagic) +{ + int bitlen; + bitlen = BN_num_bits(dsa->p); + if ((bitlen & 7) || (BN_num_bits(dsa->q) != 160) + || (BN_num_bits(dsa->g) > bitlen)) + goto badkey; + if (ispub) { + if (BN_num_bits(dsa->pub_key) > bitlen) + goto badkey; + *pmagic = MS_DSS1MAGIC; + } else { + if (BN_num_bits(dsa->priv_key) > 160) + goto badkey; + *pmagic = MS_DSS2MAGIC; + } + + return bitlen; + badkey: + PEMerr(PEM_F_CHECK_BITLEN_DSA, PEM_R_UNSUPPORTED_KEY_COMPONENTS); + return 0; +} + +static int check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *pmagic) +{ + int nbyte, hnbyte, bitlen; + if (BN_num_bits(rsa->e) > 32) + goto badkey; + bitlen = BN_num_bits(rsa->n); + nbyte = BN_num_bytes(rsa->n); + hnbyte = (BN_num_bits(rsa->n) + 15) >> 4; + if (ispub) { + *pmagic = MS_RSA1MAGIC; + return bitlen; + } else { + *pmagic = MS_RSA2MAGIC; + /* + * For private key each component must fit within nbyte or hnbyte. + */ + if (BN_num_bytes(rsa->d) > nbyte) + goto badkey; + if ((BN_num_bytes(rsa->iqmp) > hnbyte) + || (BN_num_bytes(rsa->p) > hnbyte) + || (BN_num_bytes(rsa->q) > hnbyte) + || (BN_num_bytes(rsa->dmp1) > hnbyte) + || (BN_num_bytes(rsa->dmq1) > hnbyte)) + goto badkey; + } + return bitlen; + badkey: + PEMerr(PEM_F_CHECK_BITLEN_RSA, PEM_R_UNSUPPORTED_KEY_COMPONENTS); + return 0; +} + +static void write_rsa(unsigned char **out, RSA *rsa, int ispub) +{ + int nbyte, hnbyte; + nbyte = BN_num_bytes(rsa->n); + hnbyte = (BN_num_bits(rsa->n) + 15) >> 4; + write_lebn(out, rsa->e, 4); + write_lebn(out, rsa->n, -1); + if (ispub) + return; + write_lebn(out, rsa->p, hnbyte); + write_lebn(out, rsa->q, hnbyte); + write_lebn(out, rsa->dmp1, hnbyte); + write_lebn(out, rsa->dmq1, hnbyte); + write_lebn(out, rsa->iqmp, hnbyte); + write_lebn(out, rsa->d, nbyte); +} + +static void write_dsa(unsigned char **out, DSA *dsa, int ispub) +{ + int nbyte; + nbyte = BN_num_bytes(dsa->p); + write_lebn(out, dsa->p, nbyte); + write_lebn(out, dsa->q, 20); + write_lebn(out, dsa->g, nbyte); + if (ispub) + write_lebn(out, dsa->pub_key, nbyte); + else + write_lebn(out, dsa->priv_key, 20); + /* Set "invalid" for seed structure values */ + memset(*out, 0xff, 24); + *out += 24; + return; +} + +int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk) +{ + return do_i2b_bio(out, pk, 0); +} + +int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk) +{ + return do_i2b_bio(out, pk, 1); +} + +# ifndef OPENSSL_NO_RC4 + +static int do_PVK_header(const unsigned char **in, unsigned int length, + int skip_magic, + unsigned int *psaltlen, unsigned int *pkeylen) +{ + const unsigned char *p = *in; + unsigned int pvk_magic, is_encrypted; + if (skip_magic) { + if (length < 20) { + PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); + return 0; + } + length -= 20; + } else { + if (length < 24) { + PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); + return 0; + } + length -= 24; + pvk_magic = read_ledword(&p); + if (pvk_magic != MS_PVKMAGIC) { + PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER); + return 0; + } + } + /* Skip reserved */ + p += 4; + /* + * keytype = + */ read_ledword(&p); + is_encrypted = read_ledword(&p); + *psaltlen = read_ledword(&p); + *pkeylen = read_ledword(&p); + + if (is_encrypted && !*psaltlen) { + PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_INCONSISTENT_HEADER); + return 0; + } + + *in = p; + return 1; +} + +static int derive_pvk_key(unsigned char *key, + const unsigned char *salt, unsigned int saltlen, + const unsigned char *pass, int passlen) +{ + EVP_MD_CTX mctx; + int rv = 1; + EVP_MD_CTX_init(&mctx); + if (!EVP_DigestInit_ex(&mctx, EVP_sha1(), NULL) + || !EVP_DigestUpdate(&mctx, salt, saltlen) + || !EVP_DigestUpdate(&mctx, pass, passlen) + || !EVP_DigestFinal_ex(&mctx, key, NULL)) + rv = 0; + + EVP_MD_CTX_cleanup(&mctx); + return rv; +} + +static EVP_PKEY *do_PVK_body(const unsigned char **in, + unsigned int saltlen, unsigned int keylen, + pem_password_cb *cb, void *u) +{ + EVP_PKEY *ret = NULL; + const unsigned char *p = *in; + unsigned int magic; + unsigned char *enctmp = NULL, *q; + EVP_CIPHER_CTX cctx; + EVP_CIPHER_CTX_init(&cctx); + if (saltlen) { + char psbuf[PEM_BUFSIZE]; + unsigned char keybuf[20]; + int enctmplen, inlen; + if (cb) + inlen = cb(psbuf, PEM_BUFSIZE, 0, u); + else + inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u); + if (inlen <= 0) { + PEMerr(PEM_F_DO_PVK_BODY, PEM_R_BAD_PASSWORD_READ); + return NULL; + } + enctmp = OPENSSL_malloc(keylen + 8); + if (!enctmp) { + PEMerr(PEM_F_DO_PVK_BODY, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (!derive_pvk_key(keybuf, p, saltlen, + (unsigned char *)psbuf, inlen)) + return NULL; + p += saltlen; + /* Copy BLOBHEADER across, decrypt rest */ + memcpy(enctmp, p, 8); + p += 8; + if (keylen < 8) { + PEMerr(PEM_F_DO_PVK_BODY, PEM_R_PVK_TOO_SHORT); + return NULL; + } + inlen = keylen - 8; + q = enctmp + 8; + if (!EVP_DecryptInit_ex(&cctx, EVP_rc4(), NULL, keybuf, NULL)) + goto err; + if (!EVP_DecryptUpdate(&cctx, q, &enctmplen, p, inlen)) + goto err; + if (!EVP_DecryptFinal_ex(&cctx, q + enctmplen, &enctmplen)) + goto err; + magic = read_ledword((const unsigned char **)&q); + if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) { + q = enctmp + 8; + memset(keybuf + 5, 0, 11); + if (!EVP_DecryptInit_ex(&cctx, EVP_rc4(), NULL, keybuf, NULL)) + goto err; + OPENSSL_cleanse(keybuf, 20); + if (!EVP_DecryptUpdate(&cctx, q, &enctmplen, p, inlen)) + goto err; + if (!EVP_DecryptFinal_ex(&cctx, q + enctmplen, &enctmplen)) + goto err; + magic = read_ledword((const unsigned char **)&q); + if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) { + PEMerr(PEM_F_DO_PVK_BODY, PEM_R_BAD_DECRYPT); + goto err; + } + } else + OPENSSL_cleanse(keybuf, 20); + p = enctmp; + } + + ret = b2i_PrivateKey(&p, keylen); + err: + EVP_CIPHER_CTX_cleanup(&cctx); + if (enctmp && saltlen) + OPENSSL_free(enctmp); + return ret; +} + +EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u) +{ + unsigned char pvk_hdr[24], *buf = NULL; + const unsigned char *p; + int buflen; + EVP_PKEY *ret = NULL; + unsigned int saltlen, keylen; + if (BIO_read(in, pvk_hdr, 24) != 24) { + PEMerr(PEM_F_B2I_PVK_BIO, PEM_R_PVK_DATA_TOO_SHORT); + return NULL; + } + p = pvk_hdr; + + if (!do_PVK_header(&p, 24, 0, &saltlen, &keylen)) + return 0; + buflen = (int)keylen + saltlen; + buf = OPENSSL_malloc(buflen); + if (!buf) { + PEMerr(PEM_F_B2I_PVK_BIO, ERR_R_MALLOC_FAILURE); + return 0; + } + p = buf; + if (BIO_read(in, buf, buflen) != buflen) { + PEMerr(PEM_F_B2I_PVK_BIO, PEM_R_PVK_DATA_TOO_SHORT); + goto err; + } + ret = do_PVK_body(&p, saltlen, keylen, cb, u); + + err: + if (buf) { + OPENSSL_cleanse(buf, buflen); + OPENSSL_free(buf); + } + return ret; +} + +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; + if (!out) + return outlen; + if (*out) + p = *out; + else { + p = OPENSSL_malloc(outlen); + if (!p) { + PEMerr(PEM_F_I2B_PVK, ERR_R_MALLOC_FAILURE); + return -1; + } + *out = p; + } + + 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) { + 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_cleanup(&cctx); + return outlen; + + error: + EVP_CIPHER_CTX_cleanup(&cctx); + return -1; +} + +int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, + pem_password_cb *cb, void *u) +{ + unsigned char *tmp = NULL; + int outlen, wrlen; + outlen = i2b_PVK(&tmp, pk, enclevel, cb, u); + if (outlen < 0) + return -1; + wrlen = BIO_write(out, tmp, outlen); + OPENSSL_free(tmp); + if (wrlen == outlen) { + PEMerr(PEM_F_I2B_PVK_BIO, PEM_R_BIO_WRITE_FAILURE); + return outlen; + } + return -1; +} + +# endif + +#endif |
