1/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
2 * 2006.
3 */
4/* ====================================================================
5 * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this
20 *    software must display the following acknowledgment:
21 *    "This product includes software developed by the OpenSSL Project
22 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23 *
24 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25 *    endorse or promote products derived from this software without
26 *    prior written permission. For written permission, please contact
27 *    licensing@OpenSSL.org.
28 *
29 * 5. Products derived from this software may not be called "OpenSSL"
30 *    nor may "OpenSSL" appear in their names without prior written
31 *    permission of the OpenSSL Project.
32 *
33 * 6. Redistributions of any form whatsoever must retain the following
34 *    acknowledgment:
35 *    "This product includes software developed by the OpenSSL Project
36 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49 * OF THE POSSIBILITY OF SUCH DAMAGE.
50 * ====================================================================
51 *
52 * This product includes cryptographic software written by Eric Young
53 * (eay@cryptsoft.com).  This product includes software written by Tim
54 * Hudson (tjh@cryptsoft.com). */
55
56#include <openssl/evp.h>
57
58#include <openssl/digest.h>
59#include <openssl/bn.h>
60#include <openssl/bytestring.h>
61#include <openssl/dsa.h>
62#include <openssl/err.h>
63
64#include "internal.h"
65
66
67static int dsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
68  // See RFC 3279, section 2.3.2.
69
70  // Parameters may or may not be present.
71  DSA *dsa;
72  if (CBS_len(params) == 0) {
73    dsa = DSA_new();
74    if (dsa == NULL) {
75      return 0;
76    }
77  } else {
78    dsa = DSA_parse_parameters(params);
79    if (dsa == NULL || CBS_len(params) != 0) {
80      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
81      goto err;
82    }
83  }
84
85  dsa->pub_key = BN_new();
86  if (dsa->pub_key == NULL) {
87    goto err;
88  }
89
90  if (!BN_parse_asn1_unsigned(key, dsa->pub_key) ||
91      CBS_len(key) != 0) {
92    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
93    goto err;
94  }
95
96  EVP_PKEY_assign_DSA(out, dsa);
97  return 1;
98
99err:
100  DSA_free(dsa);
101  return 0;
102}
103
104static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) {
105  const DSA *dsa = key->pkey.dsa;
106  const int has_params = dsa->p != NULL && dsa->q != NULL && dsa->g != NULL;
107
108  // See RFC 5480, section 2.
109  CBB spki, algorithm, oid, key_bitstring;
110  if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
111      !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
112      !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
113      !CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) ||
114      (has_params &&
115       !DSA_marshal_parameters(&algorithm, dsa)) ||
116      !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
117      !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
118      !BN_marshal_asn1(&key_bitstring, dsa->pub_key) ||
119      !CBB_flush(out)) {
120    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
121    return 0;
122  }
123
124  return 1;
125}
126
127static int dsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
128  // See PKCS#11, v2.40, section 2.5.
129
130  // Decode parameters.
131  BN_CTX *ctx = NULL;
132  DSA *dsa = DSA_parse_parameters(params);
133  if (dsa == NULL || CBS_len(params) != 0) {
134    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
135    goto err;
136  }
137
138  dsa->priv_key = BN_new();
139  dsa->pub_key = BN_new();
140  if (dsa->priv_key == NULL || dsa->pub_key == NULL) {
141    goto err;
142  }
143
144  // Decode the key.
145  if (!BN_parse_asn1_unsigned(key, dsa->priv_key) ||
146      CBS_len(key) != 0) {
147    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
148    goto err;
149  }
150
151  // Calculate the public key.
152  ctx = BN_CTX_new();
153  if (ctx == NULL ||
154      !BN_mod_exp_mont_consttime(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p,
155                                 ctx, NULL)) {
156    goto err;
157  }
158
159  BN_CTX_free(ctx);
160  EVP_PKEY_assign_DSA(out, dsa);
161  return 1;
162
163err:
164  BN_CTX_free(ctx);
165  DSA_free(dsa);
166  return 0;
167}
168
169static int dsa_priv_encode(CBB *out, const EVP_PKEY *key) {
170  const DSA *dsa = key->pkey.dsa;
171  if (dsa == NULL || dsa->priv_key == NULL) {
172    OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
173    return 0;
174  }
175
176  // See PKCS#11, v2.40, section 2.5.
177  CBB pkcs8, algorithm, oid, private_key;
178  if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
179      !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
180      !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
181      !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
182      !CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) ||
183      !DSA_marshal_parameters(&algorithm, dsa) ||
184      !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
185      !BN_marshal_asn1(&private_key, dsa->priv_key) ||
186      !CBB_flush(out)) {
187    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
188    return 0;
189  }
190
191  return 1;
192}
193
194static int int_dsa_size(const EVP_PKEY *pkey) {
195  return DSA_size(pkey->pkey.dsa);
196}
197
198static int dsa_bits(const EVP_PKEY *pkey) {
199  return BN_num_bits(pkey->pkey.dsa->p);
200}
201
202static int dsa_missing_parameters(const EVP_PKEY *pkey) {
203  DSA *dsa;
204  dsa = pkey->pkey.dsa;
205  if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
206    return 1;
207  }
208  return 0;
209}
210
211static int dup_bn_into(BIGNUM **out, BIGNUM *src) {
212  BIGNUM *a;
213
214  a = BN_dup(src);
215  if (a == NULL) {
216    return 0;
217  }
218  BN_free(*out);
219  *out = a;
220
221  return 1;
222}
223
224static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
225  if (!dup_bn_into(&to->pkey.dsa->p, from->pkey.dsa->p) ||
226      !dup_bn_into(&to->pkey.dsa->q, from->pkey.dsa->q) ||
227      !dup_bn_into(&to->pkey.dsa->g, from->pkey.dsa->g)) {
228    return 0;
229  }
230
231  return 1;
232}
233
234static int dsa_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
235  return BN_cmp(a->pkey.dsa->p, b->pkey.dsa->p) == 0 &&
236         BN_cmp(a->pkey.dsa->q, b->pkey.dsa->q) == 0 &&
237         BN_cmp(a->pkey.dsa->g, b->pkey.dsa->g) == 0;
238}
239
240static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
241  return BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) == 0;
242}
243
244static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); }
245
246const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = {
247  EVP_PKEY_DSA,
248  // 1.2.840.10040.4.1
249  {0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01}, 7,
250
251  dsa_pub_decode,
252  dsa_pub_encode,
253  dsa_pub_cmp,
254
255  dsa_priv_decode,
256  dsa_priv_encode,
257
258  NULL /* pkey_opaque */,
259
260  int_dsa_size,
261  dsa_bits,
262
263  dsa_missing_parameters,
264  dsa_copy_parameters,
265  dsa_cmp_parameters,
266
267  int_dsa_free,
268};
269