X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fx509%2Fx_pubkey.c;h=c240a5f5677f9ea3056eb2c531b6df3778744a54;hp=76635b8952365dffb8f248176a206a8b73bf629b;hb=7674e92324648b59786d86d8e9014bbaed4e6d07;hpb=26a7d938c9bf932a55cb5e4e02abb48fe395c5cd diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c index 76635b8952..c240a5f567 100644 --- a/crypto/x509/x_pubkey.c +++ b/crypto/x509/x_pubkey.c @@ -1,21 +1,28 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* + * DSA low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include #include "internal/cryptlib.h" #include #include -#include "internal/asn1_int.h" -#include "internal/evp_int.h" -#include "internal/x509_int.h" +#include "crypto/asn1.h" +#include "crypto/evp.h" +#include "crypto/x509.h" #include #include +#include struct X509_pubkey_st { X509_ALGOR *algor; @@ -23,7 +30,7 @@ struct X509_pubkey_st { EVP_PKEY *pkey; }; -static int x509_pubkey_decode(EVP_PKEY **pk, X509_PUBKEY *key); +static int x509_pubkey_decode(EVP_PKEY **pk, const X509_PUBKEY *key); /* Minor tweak to operation: free up EVP_PKEY */ static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, @@ -36,6 +43,7 @@ static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, /* Attempt to decode public key and cache in pubkey structure. */ X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; EVP_PKEY_free(pubkey->pkey); + pubkey->pkey = NULL; /* * Opportunistically decode the key but remove any non fatal errors * from the queue. Subsequent explicit attempts to decode/use the key @@ -55,7 +63,9 @@ ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { } ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_PUBKEY) +/* TODO should better be called X509_PUBKEY_set1 */ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) { X509_PUBKEY *pk = NULL; @@ -63,11 +73,15 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) if (x == NULL) return 0; - if ((pk = X509_PUBKEY_new()) == NULL) - goto error; + if (pkey == NULL) + goto unsupported; - if (pkey->ameth) { - if (pkey->ameth->pub_encode) { + if (pkey->ameth != NULL) { + if ((pk = X509_PUBKEY_new()) == NULL) { + X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); + goto error; + } + if (pkey->ameth->pub_encode != NULL) { if (!pkey->ameth->pub_encode(pk, pkey)) { X509err(X509_F_X509_PUBKEY_SET, X509_R_PUBLIC_KEY_ENCODE_ERROR); @@ -77,17 +91,54 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) X509err(X509_F_X509_PUBKEY_SET, X509_R_METHOD_NOT_SUPPORTED); goto error; } - } else { - X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM); - goto error; + } else if (pkey->keymgmt != NULL) { + BIO *bmem = BIO_new(BIO_s_mem()); + const char *serprop = OSSL_SERIALIZER_PUBKEY_TO_DER_PQ; + OSSL_SERIALIZER_CTX *sctx = + OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(pkey, serprop); + + if (OSSL_SERIALIZER_to_bio(sctx, bmem)) { + const unsigned char *der = NULL; + long derlen = BIO_get_mem_data(bmem, (char **)&der); + + pk = d2i_X509_PUBKEY(NULL, &der, derlen); + } + + OSSL_SERIALIZER_CTX_free(sctx); + BIO_free(bmem); } + if (pk == NULL) + goto unsupported; + X509_PUBKEY_free(*x); + if (!EVP_PKEY_up_ref(pkey)) { + X509err(X509_F_X509_PUBKEY_SET, ERR_R_INTERNAL_ERROR); + goto error; + } *x = pk; + + /* + * pk->pkey is NULL when using the legacy routine, but is non-NULL when + * going through the serializer, and for all intents and purposes, it's + * a perfect copy of |pkey|, just not the same instance. In that case, + * we could simply return early, right here. + * However, in the interest of being cautious leaning on paranoia, some + * application might very well depend on the passed |pkey| being used + * and none other, so we spend a few more cycles throwing away the newly + * created |pk->pkey| and replace it with |pkey|. + * TODO(3.0) Investigate if it's safe to change to simply return here + * if |pk->pkey != NULL|. + */ + if (pk->pkey != NULL) + EVP_PKEY_free(pk->pkey); + pk->pkey = pkey; - EVP_PKEY_up_ref(pkey); return 1; + unsupported: + X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM); + error: X509_PUBKEY_free(pk); return 0; @@ -100,8 +151,8 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) */ -static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key) - { +static int x509_pubkey_decode(EVP_PKEY **ppkey, const X509_PUBKEY *key) +{ EVP_PKEY *pkey = EVP_PKEY_new(); if (pkey == NULL) { @@ -137,7 +188,7 @@ static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key) return 0; } -EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key) +EVP_PKEY *X509_PUBKEY_get0(const X509_PUBKEY *key) { EVP_PKEY *ret = NULL; @@ -165,11 +216,14 @@ EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key) return NULL; } -EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) +EVP_PKEY *X509_PUBKEY_get(const X509_PUBKEY *key) { EVP_PKEY *ret = X509_PUBKEY_get0(key); - if (ret != NULL) - EVP_PKEY_up_ref(ret); + + if (ret != NULL && !EVP_PKEY_up_ref(ret)) { + X509err(X509_F_X509_PUBKEY_GET, ERR_R_INTERNAL_ERROR); + ret = NULL; + } return ret; } @@ -183,32 +237,71 @@ EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length) X509_PUBKEY *xpk; EVP_PKEY *pktmp; const unsigned char *q; + q = *pp; xpk = d2i_X509_PUBKEY(NULL, &q, length); - if (!xpk) + if (xpk == NULL) return NULL; pktmp = X509_PUBKEY_get(xpk); X509_PUBKEY_free(xpk); - if (!pktmp) + if (pktmp == NULL) return NULL; *pp = q; - if (a) { + if (a != NULL) { EVP_PKEY_free(*a); *a = pktmp; } return pktmp; } -int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp) +int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp) { - X509_PUBKEY *xpk = NULL; - int ret; - if (!a) - return 0; - if (!X509_PUBKEY_set(&xpk, a)) + int ret = -1; + + if (a == NULL) return 0; - ret = i2d_X509_PUBKEY(xpk, pp); - X509_PUBKEY_free(xpk); + if (a->ameth != NULL) { + X509_PUBKEY *xpk = NULL; + + if ((xpk = X509_PUBKEY_new()) == NULL) + return -1; + + /* pub_encode() only encode parameters, not the key itself */ + if (a->ameth->pub_encode != NULL && a->ameth->pub_encode(xpk, a)) { + xpk->pkey = (EVP_PKEY *)a; + ret = i2d_X509_PUBKEY(xpk, pp); + xpk->pkey = NULL; + } + X509_PUBKEY_free(xpk); + } else if (a->keymgmt != NULL) { + const char *serprop = OSSL_SERIALIZER_PUBKEY_TO_DER_PQ; + OSSL_SERIALIZER_CTX *ctx = + OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(a, serprop); + BIO *out = BIO_new(BIO_s_mem()); + BUF_MEM *buf = NULL; + + if (ctx != NULL + && out != NULL + && OSSL_SERIALIZER_CTX_get_serializer(ctx) != NULL + && OSSL_SERIALIZER_to_bio(ctx, out) + && BIO_get_mem_ptr(out, &buf) > 0) { + ret = buf->length; + + if (pp != NULL) { + if (*pp == NULL) { + *pp = (unsigned char *)buf->data; + buf->length = 0; + buf->data = NULL; + } else { + memcpy(*pp, buf->data, ret); + *pp += ret; + } + } + } + BIO_free(out); + OSSL_SERIALIZER_CTX_free(ctx); + } + return ret; } @@ -221,23 +314,24 @@ RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length) EVP_PKEY *pkey; RSA *key; const unsigned char *q; + q = *pp; pkey = d2i_PUBKEY(NULL, &q, length); - if (!pkey) + if (pkey == NULL) return NULL; key = EVP_PKEY_get1_RSA(pkey); EVP_PKEY_free(pkey); - if (!key) + if (key == NULL) return NULL; *pp = q; - if (a) { + if (a != NULL) { RSA_free(*a); *a = key; } return key; } -int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp) +int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp) { EVP_PKEY *pktmp; int ret; @@ -246,10 +340,11 @@ int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp) pktmp = EVP_PKEY_new(); if (pktmp == NULL) { ASN1err(ASN1_F_I2D_RSA_PUBKEY, ERR_R_MALLOC_FAILURE); - return 0; + return -1; } - EVP_PKEY_set1_RSA(pktmp, a); + (void)EVP_PKEY_assign_RSA(pktmp, (RSA *)a); ret = i2d_PUBKEY(pktmp, pp); + pktmp->pkey.ptr = NULL; EVP_PKEY_free(pktmp); return ret; } @@ -261,23 +356,24 @@ DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length) EVP_PKEY *pkey; DSA *key; const unsigned char *q; + q = *pp; pkey = d2i_PUBKEY(NULL, &q, length); - if (!pkey) + if (pkey == NULL) return NULL; key = EVP_PKEY_get1_DSA(pkey); EVP_PKEY_free(pkey); - if (!key) + if (key == NULL) return NULL; *pp = q; - if (a) { + if (a != NULL) { DSA_free(*a); *a = key; } return key; } -int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp) +int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp) { EVP_PKEY *pktmp; int ret; @@ -286,10 +382,11 @@ int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp) pktmp = EVP_PKEY_new(); if (pktmp == NULL) { ASN1err(ASN1_F_I2D_DSA_PUBKEY, ERR_R_MALLOC_FAILURE); - return 0; + return -1; } - EVP_PKEY_set1_DSA(pktmp, a); + (void)EVP_PKEY_assign_DSA(pktmp, (DSA *)a); ret = i2d_PUBKEY(pktmp, pp); + pktmp->pkey.ptr = NULL; EVP_PKEY_free(pktmp); return ret; } @@ -301,34 +398,37 @@ EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length) EVP_PKEY *pkey; EC_KEY *key; const unsigned char *q; + q = *pp; pkey = d2i_PUBKEY(NULL, &q, length); - if (!pkey) + if (pkey == NULL) return NULL; key = EVP_PKEY_get1_EC_KEY(pkey); EVP_PKEY_free(pkey); - if (!key) + if (key == NULL) return NULL; *pp = q; - if (a) { + if (a != NULL) { EC_KEY_free(*a); *a = key; } return key; } -int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp) +int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp) { EVP_PKEY *pktmp; int ret; - if (!a) + + if (a == NULL) return 0; if ((pktmp = EVP_PKEY_new()) == NULL) { ASN1err(ASN1_F_I2D_EC_PUBKEY, ERR_R_MALLOC_FAILURE); - return 0; + return -1; } - EVP_PKEY_set1_EC_KEY(pktmp, a); + (void)EVP_PKEY_assign_EC_KEY(pktmp, (EC_KEY *)a); ret = i2d_PUBKEY(pktmp, pp); + pktmp->pkey.ptr = NULL; EVP_PKEY_free(pktmp); return ret; } @@ -353,7 +453,7 @@ int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj, int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, const unsigned char **pk, int *ppklen, - X509_ALGOR **pa, X509_PUBKEY *pub) + X509_ALGOR **pa, const X509_PUBKEY *pub) { if (ppkalg) *ppkalg = pub->algor->algorithm;