diff options
author | David Benjamin <davidben@chromium.org> | 2016-01-30 09:51:01 +0300 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2016-02-17 03:26:01 +0300 |
commit | fda22a75730d8982baf8a567201f6254d47c9572 (patch) | |
tree | 53a33e5ed4a12f24849b7836f56c2fe6cb84873c /crypto | |
parent | 3cadf63c68c26c2f5df2f6f2a1358db4772f0163 (diff) |
Reimplement DSA parsing logic with crypto/asn1.
Functions which lose object reuse and need auditing:
- d2i_DSA_SIG
- d2i_DSAPublicKey
- d2i_DSAPrivateKey
- d2i_DSAparams
BUG=499653
Change-Id: I1cc2ae10e1e77eb57da3a858ac8734a95715ce4b
Reviewed-on: https://boringssl-review.googlesource.com/7022
Reviewed-by: Adam Langley <agl@google.com>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/dsa/dsa.c | 15 | ||||
-rw-r--r-- | crypto/dsa/dsa_asn1.c | 306 | ||||
-rw-r--r-- | crypto/err/dsa.errordata | 3 |
3 files changed, 269 insertions, 55 deletions
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c index 2a9524a3..3b269d4f 100644 --- a/crypto/dsa/dsa.c +++ b/crypto/dsa/dsa.c @@ -392,6 +392,21 @@ err: return ok; } +DSA *DSAparams_dup(const DSA *dsa) { + DSA *ret = DSA_new(); + if (ret == NULL) { + return NULL; + } + ret->p = BN_dup(dsa->p); + ret->q = BN_dup(dsa->q); + ret->g = BN_dup(dsa->g); + if (ret->p == NULL || ret->q == NULL || ret->g == NULL) { + DSA_free(ret); + return NULL; + } + return ret; +} + int DSA_generate_key(DSA *dsa) { int ok = 0; BN_CTX *ctx = NULL; diff --git a/crypto/dsa/dsa_asn1.c b/crypto/dsa/dsa_asn1.c index 4df561d6..d7b826cc 100644 --- a/crypto/dsa/dsa_asn1.c +++ b/crypto/dsa/dsa_asn1.c @@ -54,87 +54,283 @@ #include <openssl/dsa.h> -#include <string.h> +#include <assert.h> -#include <openssl/asn1.h> -#include <openssl/asn1t.h> +#include <openssl/bn.h> +#include <openssl/bytestring.h> #include <openssl/err.h> #include <openssl/mem.h> #include "internal.h" +#include "../bytestring/internal.h" -static int dsa_sig_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, - void *exarg) { - if (operation != ASN1_OP_NEW_PRE) { - return 1; +static int parse_integer(CBS *cbs, BIGNUM **out) { + assert(*out == NULL); + *out = BN_new(); + if (*out == NULL) { + return 0; + } + return BN_parse_asn1_unsigned(cbs, *out); +} + +static int marshal_integer(CBB *cbb, BIGNUM *bn) { + if (bn == NULL) { + /* A DSA object may be missing some components. */ + OPENSSL_PUT_ERROR(DSA, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + return BN_marshal_asn1(cbb, bn); +} + +DSA_SIG *DSA_SIG_parse(CBS *cbs) { + DSA_SIG *ret = DSA_SIG_new(); + if (ret == NULL) { + return NULL; + } + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->r) || + !parse_integer(&child, &ret->s) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(DSA, DSA_R_DECODE_ERROR); + DSA_SIG_free(ret); + return NULL; } + return ret; +} - DSA_SIG *sig; - sig = OPENSSL_malloc(sizeof(DSA_SIG)); - if (!sig) { - OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE); +int DSA_SIG_marshal(CBB *cbb, const DSA_SIG *sig) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !marshal_integer(&child, sig->r) || + !marshal_integer(&child, sig->s) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(DSA, DSA_R_ENCODE_ERROR); return 0; } + return 1; +} + +DSA *DSA_parse_public_key(CBS *cbs) { + DSA *ret = DSA_new(); + if (ret == NULL) { + return NULL; + } + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->pub_key) || + !parse_integer(&child, &ret->p) || + !parse_integer(&child, &ret->q) || + !parse_integer(&child, &ret->g) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(DSA, DSA_R_DECODE_ERROR); + DSA_free(ret); + return NULL; + } + return ret; +} - memset(sig, 0, sizeof(DSA_SIG)); - *pval = (ASN1_VALUE *)sig; - return 2; +int DSA_marshal_public_key(CBB *cbb, const DSA *dsa) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !marshal_integer(&child, dsa->pub_key) || + !marshal_integer(&child, dsa->p) || + !marshal_integer(&child, dsa->q) || + !marshal_integer(&child, dsa->g) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(DSA, DSA_R_ENCODE_ERROR); + return 0; + } + return 1; } -ASN1_SEQUENCE_cb(DSA_SIG, dsa_sig_cb) = { - ASN1_SIMPLE(DSA_SIG, r, CBIGNUM), - ASN1_SIMPLE(DSA_SIG, s, CBIGNUM)} ASN1_SEQUENCE_END_cb(DSA_SIG, DSA_SIG); +DSA *DSA_parse_parameters(CBS *cbs) { + DSA *ret = DSA_new(); + if (ret == NULL) { + return NULL; + } + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->p) || + !parse_integer(&child, &ret->q) || + !parse_integer(&child, &ret->g) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(DSA, DSA_R_DECODE_ERROR); + DSA_free(ret); + return NULL; + } + return ret; +} -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA_SIG, DSA_SIG, DSA_SIG); +int DSA_marshal_parameters(CBB *cbb, const DSA *dsa) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !marshal_integer(&child, dsa->p) || + !marshal_integer(&child, dsa->q) || + !marshal_integer(&child, dsa->g) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(DSA, DSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} +DSA *DSA_parse_private_key(CBS *cbs) { + DSA *ret = DSA_new(); + if (ret == NULL) { + return NULL; + } -static int dsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, - void *exarg) { - switch (operation) { - case ASN1_OP_NEW_PRE: - *pval = (ASN1_VALUE *)DSA_new(); - if (*pval) { - return 2; - } - return 0; + CBS child; + uint64_t version; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1_uint64(&child, &version)) { + OPENSSL_PUT_ERROR(DSA, DSA_R_DECODE_ERROR); + goto err; + } - case ASN1_OP_FREE_PRE: - DSA_free((DSA *)*pval); - *pval = NULL; - return 2; + if (version != 0) { + OPENSSL_PUT_ERROR(DSA, DSA_R_BAD_VERSION); + goto err; + } - default: - return 1; + if (!parse_integer(&child, &ret->p) || + !parse_integer(&child, &ret->q) || + !parse_integer(&child, &ret->g) || + !parse_integer(&child, &ret->pub_key) || + !parse_integer(&child, &ret->priv_key) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(DSA, DSA_R_DECODE_ERROR); + goto err; } + return ret; + +err: + DSA_free(ret); + return NULL; } -ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = { - ASN1_SIMPLE(DSA, version, LONG), - ASN1_SIMPLE(DSA, p, BIGNUM), - ASN1_SIMPLE(DSA, q, BIGNUM), - ASN1_SIMPLE(DSA, g, BIGNUM), - ASN1_SIMPLE(DSA, pub_key, BIGNUM), - ASN1_SIMPLE(DSA, priv_key, BIGNUM)} ASN1_SEQUENCE_END_cb(DSA, - DSAPrivateKey); +int DSA_marshal_private_key(CBB *cbb, const DSA *dsa) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&child, 0 /* version */) || + !marshal_integer(&child, dsa->p) || + !marshal_integer(&child, dsa->q) || + !marshal_integer(&child, dsa->g) || + !marshal_integer(&child, dsa->pub_key) || + !marshal_integer(&child, dsa->priv_key) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(DSA, DSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey); +DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + DSA_SIG *ret = DSA_SIG_parse(&cbs); + if (ret == NULL) { + return NULL; + } + if (out_sig != NULL) { + DSA_SIG_free(*out_sig); + *out_sig = ret; + } + *inp = CBS_data(&cbs); + return ret; +} -ASN1_SEQUENCE_cb(DSAparams, dsa_cb) = { - ASN1_SIMPLE(DSA, p, BIGNUM), ASN1_SIMPLE(DSA, q, BIGNUM), - ASN1_SIMPLE(DSA, g, BIGNUM), } ASN1_SEQUENCE_END_cb(DSA, DSAparams); +int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp) { + CBB cbb; + if (!CBB_init(&cbb, 0) || + !DSA_SIG_marshal(&cbb, in)) { + return -1; + } + return CBB_finish_i2d(&cbb, outp); +} -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAparams, DSAparams); +DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + DSA *ret = DSA_parse_public_key(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + DSA_free(*out); + *out = ret; + } + *inp = CBS_data(&cbs); + return ret; +} -ASN1_SEQUENCE_cb(DSAPublicKey, dsa_cb) = { - ASN1_SIMPLE(DSA, pub_key, BIGNUM), - ASN1_SIMPLE(DSA, p, BIGNUM), - ASN1_SIMPLE(DSA, q, BIGNUM), - ASN1_SIMPLE(DSA, g, BIGNUM) -} ASN1_SEQUENCE_END_cb(DSA, DSAPublicKey); +int i2d_DSAPublicKey(const DSA *in, uint8_t **outp) { + CBB cbb; + if (!CBB_init(&cbb, 0) || + !DSA_marshal_public_key(&cbb, in)) { + return -1; + } + return CBB_finish_i2d(&cbb, outp); +} -IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPublicKey, DSAPublicKey); +DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + DSA *ret = DSA_parse_private_key(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + DSA_free(*out); + *out = ret; + } + *inp = CBS_data(&cbs); + return ret; +} + +int i2d_DSAPrivateKey(const DSA *in, uint8_t **outp) { + CBB cbb; + if (!CBB_init(&cbb, 0) || + !DSA_marshal_private_key(&cbb, in)) { + return -1; + } + return CBB_finish_i2d(&cbb, outp); +} -DSA *DSAparams_dup(const DSA *dsa) { - return ASN1_item_dup(ASN1_ITEM_rptr(DSAparams), (DSA*) dsa); +DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + DSA *ret = DSA_parse_parameters(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + DSA_free(*out); + *out = ret; + } + *inp = CBS_data(&cbs); + return ret; +} + +int i2d_DSAparams(const DSA *in, uint8_t **outp) { + CBB cbb; + if (!CBB_init(&cbb, 0) || + !DSA_marshal_parameters(&cbb, in)) { + return -1; + } + return CBB_finish_i2d(&cbb, outp); } diff --git a/crypto/err/dsa.errordata b/crypto/err/dsa.errordata index 3c5764a1..6f4bc138 100644 --- a/crypto/err/dsa.errordata +++ b/crypto/err/dsa.errordata @@ -1,4 +1,7 @@ DSA,100,BAD_Q_VALUE +DSA,104,BAD_VERSION +DSA,105,DECODE_ERROR +DSA,106,ENCODE_ERROR DSA,101,MISSING_PARAMETERS DSA,102,MODULUS_TOO_LARGE DSA,103,NEED_NEW_SETUP_VALUES |