This allows the static linker to drop it in consumers which don't need this stuff (i.e. all sane ones), once crypto/x509 falls off. This cuts down on a number of dependencies from the core crypto bits on crypto/asn1 and crypto/x509. BUG=499653 Change-Id: I76a10a04dcc444c1ded31683df9f87725a95a4e6 Reviewed-on: https://boringssl-review.googlesource.com/5660 Reviewed-by: Adam Langley <agl@google.com>kris/onging/CECPQ3_patch15
@@ -15,6 +15,7 @@ add_library( | |||
p_rsa.c | |||
p_rsa_asn1.c | |||
pbkdf.c | |||
print.c | |||
sign.c | |||
) | |||
@@ -59,7 +59,6 @@ | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <openssl/bio.h> | |||
#include <openssl/dsa.h> | |||
#include <openssl/ec.h> | |||
#include <openssl/err.h> | |||
@@ -358,41 +357,6 @@ int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { | |||
return -2; | |||
} | |||
static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent, | |||
const char *kstr) { | |||
BIO_indent(out, indent, 128); | |||
BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr, | |||
OBJ_nid2ln(pkey->type)); | |||
return 1; | |||
} | |||
int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx) { | |||
if (pkey->ameth && pkey->ameth->pub_print) { | |||
return pkey->ameth->pub_print(out, pkey, indent, pctx); | |||
} | |||
return print_unsupported(out, pkey, indent, "Public Key"); | |||
} | |||
int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx) { | |||
if (pkey->ameth && pkey->ameth->priv_print) { | |||
return pkey->ameth->priv_print(out, pkey, indent, pctx); | |||
} | |||
return print_unsupported(out, pkey, indent, "Private Key"); | |||
} | |||
int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx) { | |||
if (pkey->ameth && pkey->ameth->param_print) { | |||
return pkey->ameth->param_print(out, pkey, indent, pctx); | |||
} | |||
return print_unsupported(out, pkey, indent, "Parameters"); | |||
} | |||
int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { | |||
return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, | |||
(void *)md); | |||
@@ -59,6 +59,8 @@ | |||
#include <openssl/base.h> | |||
#include <openssl/rsa.h> | |||
#if defined(__cplusplus) | |||
extern "C" { | |||
#endif | |||
@@ -83,7 +85,6 @@ struct evp_pkey_asn1_method_st { | |||
int (*pub_encode)(CBB *out, const EVP_PKEY *key); | |||
int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); | |||
int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); | |||
/* priv_decode decodes |params| and |key| as a PrivateKeyInfo and writes the | |||
* result into |out|. It returns one on success and zero on error. |params| is | |||
@@ -95,9 +96,6 @@ struct evp_pkey_asn1_method_st { | |||
* |out|. It returns one on success and zero on error. */ | |||
int (*priv_encode)(CBB *out, const EVP_PKEY *key); | |||
int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx); | |||
/* pkey_opaque returns 1 if the |pk| is opaque. Opaque keys are backed by | |||
* custom implementations which do not expose key material and parameters.*/ | |||
int (*pkey_opaque)(const EVP_PKEY *pk); | |||
@@ -114,8 +112,6 @@ struct evp_pkey_asn1_method_st { | |||
int (*param_missing)(const EVP_PKEY *pk); | |||
int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from); | |||
int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); | |||
int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx); | |||
void (*pkey_free)(EVP_PKEY *pkey); | |||
@@ -55,14 +55,11 @@ | |||
#include <openssl/evp.h> | |||
#include <openssl/asn1.h> | |||
#include <openssl/asn1t.h> | |||
#include <openssl/digest.h> | |||
#include <openssl/bn.h> | |||
#include <openssl/bytestring.h> | |||
#include <openssl/dsa.h> | |||
#include <openssl/err.h> | |||
#include <openssl/mem.h> | |||
#include <openssl/obj.h> | |||
#include "internal.h" | |||
@@ -244,91 +241,6 @@ static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { | |||
static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); } | |||
static void update_buflen(const BIGNUM *b, size_t *pbuflen) { | |||
size_t i; | |||
if (!b) { | |||
return; | |||
} | |||
i = BN_num_bytes(b); | |||
if (*pbuflen < i) { | |||
*pbuflen = i; | |||
} | |||
} | |||
static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) { | |||
uint8_t *m = NULL; | |||
int ret = 0; | |||
size_t buf_len = 0; | |||
const char *ktype = NULL; | |||
const BIGNUM *priv_key, *pub_key; | |||
priv_key = NULL; | |||
if (ptype == 2) { | |||
priv_key = x->priv_key; | |||
} | |||
pub_key = NULL; | |||
if (ptype > 0) { | |||
pub_key = x->pub_key; | |||
} | |||
ktype = "DSA-Parameters"; | |||
if (ptype == 2) { | |||
ktype = "Private-Key"; | |||
} else if (ptype == 1) { | |||
ktype = "Public-Key"; | |||
} | |||
update_buflen(x->p, &buf_len); | |||
update_buflen(x->q, &buf_len); | |||
update_buflen(x->g, &buf_len); | |||
update_buflen(priv_key, &buf_len); | |||
update_buflen(pub_key, &buf_len); | |||
m = OPENSSL_malloc(buf_len + 10); | |||
if (m == NULL) { | |||
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
if (priv_key) { | |||
if (!BIO_indent(bp, off, 128) || | |||
BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) { | |||
goto err; | |||
} | |||
} | |||
if (!ASN1_bn_print(bp, "priv:", priv_key, m, off) || | |||
!ASN1_bn_print(bp, "pub: ", pub_key, m, off) || | |||
!ASN1_bn_print(bp, "P: ", x->p, m, off) || | |||
!ASN1_bn_print(bp, "Q: ", x->q, m, off) || | |||
!ASN1_bn_print(bp, "G: ", x->g, m, off)) { | |||
goto err; | |||
} | |||
ret = 1; | |||
err: | |||
OPENSSL_free(m); | |||
return ret; | |||
} | |||
static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_dsa_print(bp, pkey->pkey.dsa, indent, 0); | |||
} | |||
static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_dsa_print(bp, pkey->pkey.dsa, indent, 1); | |||
} | |||
static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_dsa_print(bp, pkey->pkey.dsa, indent, 2); | |||
} | |||
static int old_dsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, | |||
int derlen) { | |||
DSA *dsa; | |||
@@ -348,11 +260,9 @@ const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = { | |||
dsa_pub_decode, | |||
dsa_pub_encode, | |||
dsa_pub_cmp, | |||
dsa_pub_print, | |||
dsa_priv_decode, | |||
dsa_priv_encode, | |||
dsa_priv_print, | |||
NULL /* pkey_opaque */, | |||
NULL /* pkey_supports_digest */, | |||
@@ -363,7 +273,6 @@ const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = { | |||
dsa_missing_parameters, | |||
dsa_copy_parameters, | |||
dsa_cmp_parameters, | |||
dsa_param_print, | |||
int_dsa_free, | |||
old_dsa_priv_decode, | |||
@@ -55,14 +55,12 @@ | |||
#include <openssl/evp.h> | |||
#include <openssl/asn1t.h> | |||
#include <openssl/bn.h> | |||
#include <openssl/bytestring.h> | |||
#include <openssl/ec.h> | |||
#include <openssl/ec_key.h> | |||
#include <openssl/ecdsa.h> | |||
#include <openssl/err.h> | |||
#include <openssl/mem.h> | |||
#include <openssl/obj.h> | |||
#include "internal.h" | |||
@@ -236,125 +234,6 @@ static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { | |||
static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); } | |||
static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) { | |||
uint8_t *buffer = NULL; | |||
const char *ecstr; | |||
size_t buf_len = 0, i; | |||
int ret = 0, reason = ERR_R_BIO_LIB; | |||
BN_CTX *ctx = NULL; | |||
const EC_GROUP *group; | |||
const EC_POINT *public_key; | |||
const BIGNUM *priv_key; | |||
uint8_t *pub_key_bytes = NULL; | |||
size_t pub_key_bytes_len = 0; | |||
if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { | |||
reason = ERR_R_PASSED_NULL_PARAMETER; | |||
goto err; | |||
} | |||
ctx = BN_CTX_new(); | |||
if (ctx == NULL) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
if (ktype > 0) { | |||
public_key = EC_KEY_get0_public_key(x); | |||
if (public_key != NULL) { | |||
pub_key_bytes_len = EC_POINT_point2oct( | |||
group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx); | |||
if (pub_key_bytes_len == 0) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len); | |||
if (pub_key_bytes == NULL) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
pub_key_bytes_len = | |||
EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x), | |||
pub_key_bytes, pub_key_bytes_len, ctx); | |||
if (pub_key_bytes_len == 0) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
buf_len = pub_key_bytes_len; | |||
} | |||
} | |||
if (ktype == 2) { | |||
priv_key = EC_KEY_get0_private_key(x); | |||
if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) { | |||
buf_len = i; | |||
} | |||
} else { | |||
priv_key = NULL; | |||
} | |||
if (ktype > 0) { | |||
buf_len += 10; | |||
if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
} | |||
if (ktype == 2) { | |||
ecstr = "Private-Key"; | |||
} else if (ktype == 1) { | |||
ecstr = "Public-Key"; | |||
} else { | |||
ecstr = "ECDSA-Parameters"; | |||
} | |||
if (!BIO_indent(bp, off, 128)) { | |||
goto err; | |||
} | |||
const BIGNUM *order = EC_GROUP_get0_order(group); | |||
if (BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) { | |||
goto err; | |||
} | |||
if ((priv_key != NULL) && | |||
!ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) { | |||
goto err; | |||
} | |||
if (pub_key_bytes != NULL) { | |||
BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off); | |||
} | |||
/* TODO(fork): implement */ | |||
/* | |||
if (!ECPKParameters_print(bp, group, off)) | |||
goto err; */ | |||
ret = 1; | |||
err: | |||
if (!ret) { | |||
OPENSSL_PUT_ERROR(EVP, reason); | |||
} | |||
OPENSSL_free(pub_key_bytes); | |||
BN_CTX_free(ctx); | |||
OPENSSL_free(buffer); | |||
return ret; | |||
} | |||
static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0); | |||
} | |||
static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1); | |||
} | |||
static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); | |||
} | |||
static int eckey_opaque(const EVP_PKEY *pkey) { | |||
return EC_KEY_is_opaque(pkey->pkey.ec); | |||
} | |||
@@ -377,11 +256,9 @@ const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { | |||
eckey_pub_decode, | |||
eckey_pub_encode, | |||
eckey_pub_cmp, | |||
eckey_pub_print, | |||
eckey_priv_decode, | |||
eckey_priv_encode, | |||
eckey_priv_print, | |||
eckey_opaque, | |||
0 /* pkey_supports_digest */, | |||
@@ -392,7 +269,6 @@ const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { | |||
ec_missing_parameters, | |||
ec_copy_parameters, | |||
ec_cmp_parameters, | |||
eckey_param_print, | |||
int_ec_free, | |||
old_ec_priv_decode, | |||
@@ -55,7 +55,7 @@ | |||
#include <openssl/evp.h> | |||
#include <openssl/asn1.h> | |||
#include <openssl/bn.h> | |||
#include <openssl/bytestring.h> | |||
#include <openssl/digest.h> | |||
#include <openssl/err.h> | |||
@@ -175,133 +175,6 @@ static int rsa_bits(const EVP_PKEY *pkey) { | |||
static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); } | |||
static void update_buflen(const BIGNUM *b, size_t *pbuflen) { | |||
size_t i; | |||
if (!b) { | |||
return; | |||
} | |||
i = BN_num_bytes(b); | |||
if (*pbuflen < i) { | |||
*pbuflen = i; | |||
} | |||
} | |||
static int do_rsa_print(BIO *out, const RSA *rsa, int off, | |||
int include_private) { | |||
char *str; | |||
const char *s; | |||
uint8_t *m = NULL; | |||
int ret = 0, mod_len = 0; | |||
size_t buf_len = 0; | |||
update_buflen(rsa->n, &buf_len); | |||
update_buflen(rsa->e, &buf_len); | |||
if (include_private) { | |||
update_buflen(rsa->d, &buf_len); | |||
update_buflen(rsa->p, &buf_len); | |||
update_buflen(rsa->q, &buf_len); | |||
update_buflen(rsa->dmp1, &buf_len); | |||
update_buflen(rsa->dmq1, &buf_len); | |||
update_buflen(rsa->iqmp, &buf_len); | |||
if (rsa->additional_primes != NULL) { | |||
size_t i; | |||
for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); | |||
i++) { | |||
const RSA_additional_prime *ap = | |||
sk_RSA_additional_prime_value(rsa->additional_primes, i); | |||
update_buflen(ap->prime, &buf_len); | |||
update_buflen(ap->exp, &buf_len); | |||
update_buflen(ap->coeff, &buf_len); | |||
} | |||
} | |||
} | |||
m = OPENSSL_malloc(buf_len + 10); | |||
if (m == NULL) { | |||
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
if (rsa->n != NULL) { | |||
mod_len = BN_num_bits(rsa->n); | |||
} | |||
if (!BIO_indent(out, off, 128)) { | |||
goto err; | |||
} | |||
if (include_private && rsa->d) { | |||
if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) { | |||
goto err; | |||
} | |||
str = "modulus:"; | |||
s = "publicExponent:"; | |||
} else { | |||
if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) { | |||
goto err; | |||
} | |||
str = "Modulus:"; | |||
s = "Exponent:"; | |||
} | |||
if (!ASN1_bn_print(out, str, rsa->n, m, off) || | |||
!ASN1_bn_print(out, s, rsa->e, m, off)) { | |||
goto err; | |||
} | |||
if (include_private) { | |||
if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) || | |||
!ASN1_bn_print(out, "prime1:", rsa->p, m, off) || | |||
!ASN1_bn_print(out, "prime2:", rsa->q, m, off) || | |||
!ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) || | |||
!ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) || | |||
!ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) { | |||
goto err; | |||
} | |||
if (rsa->additional_primes != NULL && | |||
sk_RSA_additional_prime_num(rsa->additional_primes) > 0) { | |||
size_t i; | |||
if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) { | |||
goto err; | |||
} | |||
for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); | |||
i++) { | |||
const RSA_additional_prime *ap = | |||
sk_RSA_additional_prime_value(rsa->additional_primes, i); | |||
if (BIO_printf(out, "otherPrimeInfo (prime %u):\n", | |||
(unsigned)(i + 3)) <= 0 || | |||
!ASN1_bn_print(out, "prime:", ap->prime, m, off) || | |||
!ASN1_bn_print(out, "exponent:", ap->exp, m, off) || | |||
!ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) { | |||
goto err; | |||
} | |||
} | |||
} | |||
} | |||
ret = 1; | |||
err: | |||
OPENSSL_free(m); | |||
return ret; | |||
} | |||
static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_rsa_print(bp, pkey->pkey.rsa, indent, 0); | |||
} | |||
static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_rsa_print(bp, pkey->pkey.rsa, indent, 1); | |||
} | |||
static int old_rsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, | |||
int derlen) { | |||
RSA *rsa = d2i_RSAPrivateKey(NULL, pder, derlen); | |||
@@ -320,11 +193,9 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { | |||
rsa_pub_decode, | |||
rsa_pub_encode, | |||
rsa_pub_cmp, | |||
rsa_pub_print, | |||
rsa_priv_decode, | |||
rsa_priv_encode, | |||
rsa_priv_print, | |||
rsa_opaque, | |||
rsa_supports_digest, | |||
@@ -332,7 +203,7 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { | |||
int_rsa_size, | |||
rsa_bits, | |||
0,0,0,0, | |||
0,0,0, | |||
int_rsa_free, | |||
@@ -0,0 +1,474 @@ | |||
/* ==================================================================== | |||
* Copyright (c) 2006 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). */ | |||
#include <openssl/evp.h> | |||
#include <openssl/asn1.h> | |||
#include <openssl/bio.h> | |||
#include <openssl/bn.h> | |||
#include <openssl/dsa.h> | |||
#include <openssl/ec.h> | |||
#include <openssl/ec_key.h> | |||
#include <openssl/mem.h> | |||
#include <openssl/rsa.h> | |||
#include "../rsa/internal.h" | |||
static void update_buflen(const BIGNUM *b, size_t *pbuflen) { | |||
size_t i; | |||
if (!b) { | |||
return; | |||
} | |||
i = BN_num_bytes(b); | |||
if (*pbuflen < i) { | |||
*pbuflen = i; | |||
} | |||
} | |||
/* RSA keys. */ | |||
static int do_rsa_print(BIO *out, const RSA *rsa, int off, | |||
int include_private) { | |||
char *str; | |||
const char *s; | |||
uint8_t *m = NULL; | |||
int ret = 0, mod_len = 0; | |||
size_t buf_len = 0; | |||
update_buflen(rsa->n, &buf_len); | |||
update_buflen(rsa->e, &buf_len); | |||
if (include_private) { | |||
update_buflen(rsa->d, &buf_len); | |||
update_buflen(rsa->p, &buf_len); | |||
update_buflen(rsa->q, &buf_len); | |||
update_buflen(rsa->dmp1, &buf_len); | |||
update_buflen(rsa->dmq1, &buf_len); | |||
update_buflen(rsa->iqmp, &buf_len); | |||
if (rsa->additional_primes != NULL) { | |||
size_t i; | |||
for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); | |||
i++) { | |||
const RSA_additional_prime *ap = | |||
sk_RSA_additional_prime_value(rsa->additional_primes, i); | |||
update_buflen(ap->prime, &buf_len); | |||
update_buflen(ap->exp, &buf_len); | |||
update_buflen(ap->coeff, &buf_len); | |||
} | |||
} | |||
} | |||
m = (uint8_t *)OPENSSL_malloc(buf_len + 10); | |||
if (m == NULL) { | |||
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
if (rsa->n != NULL) { | |||
mod_len = BN_num_bits(rsa->n); | |||
} | |||
if (!BIO_indent(out, off, 128)) { | |||
goto err; | |||
} | |||
if (include_private && rsa->d) { | |||
if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) { | |||
goto err; | |||
} | |||
str = "modulus:"; | |||
s = "publicExponent:"; | |||
} else { | |||
if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) { | |||
goto err; | |||
} | |||
str = "Modulus:"; | |||
s = "Exponent:"; | |||
} | |||
if (!ASN1_bn_print(out, str, rsa->n, m, off) || | |||
!ASN1_bn_print(out, s, rsa->e, m, off)) { | |||
goto err; | |||
} | |||
if (include_private) { | |||
if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) || | |||
!ASN1_bn_print(out, "prime1:", rsa->p, m, off) || | |||
!ASN1_bn_print(out, "prime2:", rsa->q, m, off) || | |||
!ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) || | |||
!ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) || | |||
!ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) { | |||
goto err; | |||
} | |||
if (rsa->additional_primes != NULL && | |||
sk_RSA_additional_prime_num(rsa->additional_primes) > 0) { | |||
size_t i; | |||
if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) { | |||
goto err; | |||
} | |||
for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); | |||
i++) { | |||
const RSA_additional_prime *ap = | |||
sk_RSA_additional_prime_value(rsa->additional_primes, i); | |||
if (BIO_printf(out, "otherPrimeInfo (prime %u):\n", | |||
(unsigned)(i + 3)) <= 0 || | |||
!ASN1_bn_print(out, "prime:", ap->prime, m, off) || | |||
!ASN1_bn_print(out, "exponent:", ap->exp, m, off) || | |||
!ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) { | |||
goto err; | |||
} | |||
} | |||
} | |||
} | |||
ret = 1; | |||
err: | |||
OPENSSL_free(m); | |||
return ret; | |||
} | |||
static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_rsa_print(bp, pkey->pkey.rsa, indent, 0); | |||
} | |||
static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_rsa_print(bp, pkey->pkey.rsa, indent, 1); | |||
} | |||
/* DSA keys. */ | |||
static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) { | |||
uint8_t *m = NULL; | |||
int ret = 0; | |||
size_t buf_len = 0; | |||
const char *ktype = NULL; | |||
const BIGNUM *priv_key, *pub_key; | |||
priv_key = NULL; | |||
if (ptype == 2) { | |||
priv_key = x->priv_key; | |||
} | |||
pub_key = NULL; | |||
if (ptype > 0) { | |||
pub_key = x->pub_key; | |||
} | |||
ktype = "DSA-Parameters"; | |||
if (ptype == 2) { | |||
ktype = "Private-Key"; | |||
} else if (ptype == 1) { | |||
ktype = "Public-Key"; | |||
} | |||
update_buflen(x->p, &buf_len); | |||
update_buflen(x->q, &buf_len); | |||
update_buflen(x->g, &buf_len); | |||
update_buflen(priv_key, &buf_len); | |||
update_buflen(pub_key, &buf_len); | |||
m = (uint8_t *)OPENSSL_malloc(buf_len + 10); | |||
if (m == NULL) { | |||
OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
if (priv_key) { | |||
if (!BIO_indent(bp, off, 128) || | |||
BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) { | |||
goto err; | |||
} | |||
} | |||
if (!ASN1_bn_print(bp, "priv:", priv_key, m, off) || | |||
!ASN1_bn_print(bp, "pub: ", pub_key, m, off) || | |||
!ASN1_bn_print(bp, "P: ", x->p, m, off) || | |||
!ASN1_bn_print(bp, "Q: ", x->q, m, off) || | |||
!ASN1_bn_print(bp, "G: ", x->g, m, off)) { | |||
goto err; | |||
} | |||
ret = 1; | |||
err: | |||
OPENSSL_free(m); | |||
return ret; | |||
} | |||
static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_dsa_print(bp, pkey->pkey.dsa, indent, 0); | |||
} | |||
static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_dsa_print(bp, pkey->pkey.dsa, indent, 1); | |||
} | |||
static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_dsa_print(bp, pkey->pkey.dsa, indent, 2); | |||
} | |||
/* EC keys. */ | |||
static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) { | |||
uint8_t *buffer = NULL; | |||
const char *ecstr; | |||
size_t buf_len = 0, i; | |||
int ret = 0, reason = ERR_R_BIO_LIB; | |||
BIGNUM *order = NULL; | |||
BN_CTX *ctx = NULL; | |||
const EC_GROUP *group; | |||
const EC_POINT *public_key; | |||
const BIGNUM *priv_key; | |||
uint8_t *pub_key_bytes = NULL; | |||
size_t pub_key_bytes_len = 0; | |||
if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { | |||
reason = ERR_R_PASSED_NULL_PARAMETER; | |||
goto err; | |||
} | |||
ctx = BN_CTX_new(); | |||
if (ctx == NULL) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
if (ktype > 0) { | |||
public_key = EC_KEY_get0_public_key(x); | |||
if (public_key != NULL) { | |||
pub_key_bytes_len = EC_POINT_point2oct( | |||
group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx); | |||
if (pub_key_bytes_len == 0) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len); | |||
if (pub_key_bytes == NULL) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
pub_key_bytes_len = | |||
EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x), | |||
pub_key_bytes, pub_key_bytes_len, ctx); | |||
if (pub_key_bytes_len == 0) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
buf_len = pub_key_bytes_len; | |||
} | |||
} | |||
if (ktype == 2) { | |||
priv_key = EC_KEY_get0_private_key(x); | |||
if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) { | |||
buf_len = i; | |||
} | |||
} else { | |||
priv_key = NULL; | |||
} | |||
if (ktype > 0) { | |||
buf_len += 10; | |||
if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { | |||
reason = ERR_R_MALLOC_FAILURE; | |||
goto err; | |||
} | |||
} | |||
if (ktype == 2) { | |||
ecstr = "Private-Key"; | |||
} else if (ktype == 1) { | |||
ecstr = "Public-Key"; | |||
} else { | |||
ecstr = "ECDSA-Parameters"; | |||
} | |||
if (!BIO_indent(bp, off, 128)) { | |||
goto err; | |||
} | |||
order = BN_new(); | |||
if (order == NULL || !EC_GROUP_get_order(group, order, NULL) || | |||
BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) { | |||
goto err; | |||
} | |||
if ((priv_key != NULL) && | |||
!ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) { | |||
goto err; | |||
} | |||
if (pub_key_bytes != NULL) { | |||
BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off); | |||
} | |||
/* TODO(fork): implement */ | |||
/* | |||
if (!ECPKParameters_print(bp, group, off)) | |||
goto err; */ | |||
ret = 1; | |||
err: | |||
if (!ret) { | |||
OPENSSL_PUT_ERROR(EVP, reason); | |||
} | |||
OPENSSL_free(pub_key_bytes); | |||
BN_free(order); | |||
BN_CTX_free(ctx); | |||
OPENSSL_free(buffer); | |||
return ret; | |||
} | |||
static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0); | |||
} | |||
static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1); | |||
} | |||
static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *ctx) { | |||
return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); | |||
} | |||
typedef struct { | |||
int type; | |||
int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); | |||
int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx); | |||
int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx); | |||
} EVP_PKEY_PRINT_METHOD; | |||
static EVP_PKEY_PRINT_METHOD kPrintMethods[] = { | |||
{ | |||
EVP_PKEY_RSA, | |||
rsa_pub_print, | |||
rsa_priv_print, | |||
NULL /* param_print */, | |||
}, | |||
{ | |||
EVP_PKEY_DSA, | |||
dsa_pub_print, | |||
dsa_priv_print, | |||
dsa_param_print, | |||
}, | |||
{ | |||
EVP_PKEY_EC, | |||
eckey_pub_print, | |||
eckey_priv_print, | |||
eckey_param_print, | |||
}, | |||
}; | |||
static size_t kPrintMethodsLen = | |||
sizeof(kPrintMethods) / sizeof(kPrintMethods[0]); | |||
static EVP_PKEY_PRINT_METHOD *find_method(int type) { | |||
size_t i; | |||
for (i = 0; i < kPrintMethodsLen; i++) { | |||
if (kPrintMethods[i].type == type) { | |||
return &kPrintMethods[i]; | |||
} | |||
} | |||
return NULL; | |||
} | |||
static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent, | |||
const char *kstr) { | |||
BIO_indent(out, indent, 128); | |||
BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr, | |||
OBJ_nid2ln(pkey->type)); | |||
return 1; | |||
} | |||
int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx) { | |||
EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type); | |||
if (method != NULL && method->pub_print != NULL) { | |||
return method->pub_print(out, pkey, indent, pctx); | |||
} | |||
return print_unsupported(out, pkey, indent, "Public Key"); | |||
} | |||
int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx) { | |||
EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type); | |||
if (method != NULL && method->priv_print != NULL) { | |||
return method->priv_print(out, pkey, indent, pctx); | |||
} | |||
return print_unsupported(out, pkey, indent, "Private Key"); | |||
} | |||
int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent, | |||
ASN1_PCTX *pctx) { | |||
EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type); | |||
if (method != NULL && method->param_print != NULL) { | |||
return method->param_print(out, pkey, indent, pctx); | |||
} | |||
return print_unsupported(out, pkey, indent, "Parameters"); | |||
} |