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 -#include +#include -#include -#include +#include +#include #include #include #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 diff --git a/include/openssl/dsa.h b/include/openssl/dsa.h index df74bb78..8cf008b6 100644 --- a/include/openssl/dsa.h +++ b/include/openssl/dsa.h @@ -218,66 +218,41 @@ OPENSSL_EXPORT int DSA_size(const DSA *dsa); /* ASN.1 encoding. */ -/* d2i_DSA_SIG parses an ASN.1, DER-encoded, DSA signature from |len| bytes at - * |*inp|. If |out_sig| is not NULL then, on exit, a pointer to the result is - * in |*out_sig|. If |*out_sig| is already non-NULL on entry then the result is - * written directly into |*out_sig|, otherwise a fresh |DSA_SIG| is allocated. - * However, one should not depend on writing into |*out_sig| because this - * behaviour is likely to change in the future. On successful exit, |*inp| is - * advanced past the DER structure. It returns the result or NULL on error. */ -OPENSSL_EXPORT DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, - long len); - -/* i2d_DSA_SIG marshals |in| to an ASN.1, DER structure. If |outp| is not NULL - * then the result is written to |*outp| and |*outp| is advanced just past the - * output. It returns the number of bytes in the result, whether written or not, - * or a negative value on error. */ -OPENSSL_EXPORT int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp); - -/* d2i_DSAPublicKey parses an ASN.1, DER-encoded, DSA public key from |len| - * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result - * is in |*out|. If |*out| is already non-NULL on entry then the result is - * written directly into |*out|, otherwise a fresh |DSA| is allocated. - * However, one should not depend on writing into |*out| because this behaviour - * is likely to change in the future. On successful exit, |*inp| is advanced - * past the DER structure. It returns the result or NULL on error. */ -OPENSSL_EXPORT DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len); - -/* i2d_DSAPublicKey marshals a public key from |in| to an ASN.1, DER structure. - * If |outp| is not NULL then the result is written to |*outp| and |*outp| is - * advanced just past the output. It returns the number of bytes in the result, - * whether written or not, or a negative value on error. */ -OPENSSL_EXPORT int i2d_DSAPublicKey(const DSA *in, unsigned char **outp); - -/* d2i_DSAPrivateKey parses an ASN.1, DER-encoded, DSA private key from |len| - * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result - * is in |*out|. If |*out| is already non-NULL on entry then the result is - * written directly into |*out|, otherwise a fresh |DSA| is allocated. However, - * one should not depend on writing into |*out| because this behaviour is - * likely to change in the future. On successful exit, |*inp| is advanced past - * the DER structure. It returns the result or NULL on error. */ -OPENSSL_EXPORT DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len); +/* DSA_SIG_parse parses a DER-encoded DSA-Sig-Value structure from |cbs| and + * advances |cbs|. It returns a newly-allocated |DSA_SIG| or NULL on error. */ +OPENSSL_EXPORT DSA_SIG *DSA_SIG_parse(CBS *cbs); + +/* DSA_SIG_marshal marshals |sig| as a DER-encoded DSA-Sig-Value and appends the + * result to |cbb|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int DSA_SIG_marshal(CBB *cbb, const DSA_SIG *sig); + +/* DSA_parse_public_key parses a DER-encoded DSA public key from |cbs| and + * advances |cbs|. It returns a newly-allocated |DSA| or NULL on error. */ +OPENSSL_EXPORT DSA *DSA_parse_public_key(CBS *cbs); + +/* DSA_marshal_public_key marshals |dsa| as a DER-encoded DSA public key and + * appends the result to |cbb|. It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int DSA_marshal_public_key(CBB *cbb, const DSA *dsa); + +/* DSA_parse_private_key parses a DER-encoded DSA private key from |cbs| and + * advances |cbs|. It returns a newly-allocated |DSA| or NULL on error. */ +OPENSSL_EXPORT DSA *DSA_parse_private_key(CBS *cbs); + +/* DSA_marshal_private_key marshals |dsa| as a DER-encoded DSA private key and + * appends the result to |cbb|. It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int DSA_marshal_private_key(CBB *cbb, const DSA *dsa); + +/* DSA_parse_parameters parses a DER-encoded Dss-Parms structure (RFC 3279) + * from |cbs| and advances |cbs|. It returns a newly-allocated |DSA| or NULL on + * error. */ +OPENSSL_EXPORT DSA *DSA_parse_parameters(CBS *cbs); -/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure. - * If |outp| is not NULL then the result is written to |*outp| and |*outp| is - * advanced just past the output. It returns the number of bytes in the result, - * whether written or not, or a negative value on error. */ -OPENSSL_EXPORT int i2d_DSAPrivateKey(const DSA *in, unsigned char **outp); - -/* d2i_DSAparams parses ASN.1, DER-encoded, DSA parameters from |len| bytes at - * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in - * |*out|. If |*out| is already non-NULL on entry then the result is written - * directly into |*out|, otherwise a fresh |DSA| is allocated. However, one - * should not depend on writing into |*out| because this behaviour is likely to - * change in the future. On successful exit, |*inp| is advanced past the DER - * structure. It returns the result or NULL on error. */ -OPENSSL_EXPORT DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len); - -/* i2d_DSAparams marshals DSA parameters from |in| to an ASN.1, DER structure. - * If |outp| is not NULL then the result is written to |*outp| and |*outp| is - * advanced just past the output. It returns the number of bytes in the result, - * whether written or not, or a negative value on error. */ -OPENSSL_EXPORT int i2d_DSAparams(const DSA *in, unsigned char **outp); +/* DSA_marshal_parameters marshals |dsa| as a DER-encoded Dss-Parms structure + * (RFC 3447) and appends the result to |cbb|. It returns one on success and + * zero on failure. */ +OPENSSL_EXPORT int DSA_marshal_parameters(CBB *cbb, const DSA *dsa); /* Precomputation. */ @@ -313,6 +288,82 @@ OPENSSL_EXPORT int DSA_set_ex_data(DSA *d, int idx, void *arg); OPENSSL_EXPORT void *DSA_get_ex_data(const DSA *d, int idx); +/* Deprecated functions. */ + +/* d2i_DSA_SIG parses an ASN.1, DER-encoded, DSA signature from |len| bytes at + * |*inp|. If |out_sig| is not NULL then, on exit, a pointer to the result is + * in |*out_sig|. Note that, even if |*out_sig| is already non-NULL on entry, it + * will not be written to. Rather, a fresh |DSA_SIG| is allocated and the + * previous one is freed. On successful exit, |*inp| is advanced past the DER + * structure. It returns the result or NULL on error. + * + * Use |DSA_SIG_parse| instead. */ +OPENSSL_EXPORT DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, + long len); + +/* i2d_DSA_SIG marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or not, + * or a negative value on error. + * + * Use |DSA_SIG_marshal| instead. */ +OPENSSL_EXPORT int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp); + +/* d2i_DSAPublicKey parses an ASN.1, DER-encoded, DSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. Note that, even if |*ou| is already non-NULL on entry, it will + * not be written to. Rather, a fresh |DSA| is allocated and the previous one is + * freed. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. + * + * Use |DSA_parse_public_key| instead. */ +OPENSSL_EXPORT DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPublicKey marshals a public key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. + * + * Use |DSA_marshal_public_key| instead. */ +OPENSSL_EXPORT int i2d_DSAPublicKey(const DSA *in, uint8_t **outp); + +/* d2i_DSAPrivateKey parses an ASN.1, DER-encoded, DSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. Note that, even if |*out| is already non-NULL on entry, it will + * not be written to. Rather, a fresh |DSA| is allocated and the previous one is + * freed. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. + * + * Use |DSA_parse_private_key| instead. */ +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. + * + * Use |DSA_marshal_private_key| instead. */ +OPENSSL_EXPORT int i2d_DSAPrivateKey(const DSA *in, uint8_t **outp); + +/* d2i_DSAparams parses ASN.1, DER-encoded, DSA parameters from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. Note that, even if |*out| is already non-NULL on entry, it will not + * be written to. Rather, a fresh |DSA| is allocated and the previous one is + * freed. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. + * + * Use |DSA_parse_parameters| instead. */ +OPENSSL_EXPORT DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAparams marshals DSA parameters from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. + * + * Use |DSA_marshal_parameters| instead. */ +OPENSSL_EXPORT int i2d_DSAparams(const DSA *in, uint8_t **outp); + + struct dsa_st { long version; BIGNUM *p; @@ -342,5 +393,8 @@ struct dsa_st { #define DSA_R_MISSING_PARAMETERS 101 #define DSA_R_MODULUS_TOO_LARGE 102 #define DSA_R_NEED_NEW_SETUP_VALUES 103 +#define DSA_R_BAD_VERSION 104 +#define DSA_R_DECODE_ERROR 105 +#define DSA_R_ENCODE_ERROR 106 #endif /* OPENSSL_HEADER_DSA_H */