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>
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c
index 2a9524a..3b269d4 100644
--- a/crypto/dsa/dsa.c
+++ b/crypto/dsa/dsa.c
@@ -392,6 +392,21 @@
   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 4df561d..d7b826c 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;
-  }
-
-  DSA_SIG *sig;
-  sig = OPENSSL_malloc(sizeof(DSA_SIG));
-  if (!sig) {
-    OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE);
+static int parse_integer(CBS *cbs, BIGNUM **out) {
+  assert(*out == NULL);
+  *out = BN_new();
+  if (*out == NULL) {
     return 0;
   }
-
-  memset(sig, 0, sizeof(DSA_SIG));
-  *pval = (ASN1_VALUE *)sig;
-  return 2;
+  return BN_parse_asn1_unsigned(cbs, *out);
 }
 
-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);
-
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA_SIG, DSA_SIG, DSA_SIG);
-
-
-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;
-
-    case ASN1_OP_FREE_PRE:
-      DSA_free((DSA *)*pval);
-      *pval = NULL;
-      return 2;
-
-    default:
-      return 1;
+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);
 }
 
-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);
+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;
+}
 
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey);
+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;
+}
 
-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);
+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;
+}
 
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAparams, DSAparams);
+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(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);
+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, DSAPublicKey, DSAPublicKey);
+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 *DSAparams_dup(const DSA *dsa) {
-  return ASN1_item_dup(ASN1_ITEM_rptr(DSAparams), (DSA*) dsa);
+DSA *DSA_parse_private_key(CBS *cbs) {
+  DSA *ret = DSA_new();
+  if (ret == NULL) {
+    return NULL;
+  }
+
+  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;
+  }
+
+  if (version != 0) {
+    OPENSSL_PUT_ERROR(DSA, DSA_R_BAD_VERSION);
+    goto err;
+  }
+
+  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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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);
+}
+
+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 *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 3c5764a..6f4bc13 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 df74bb7..8cf008b 100644
--- a/include/openssl/dsa.h
+++ b/include/openssl/dsa.h
@@ -218,66 +218,41 @@
 
 /* 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);
+/* 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);
 
-/* 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);
+/* 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);
 
-/* 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);
+/* 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);
 
-/* 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);
+/* 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);
 
-/* 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_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);
 
-/* 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);
+/* 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);
 
-/* 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);
+/* 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_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 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 @@
 #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 */