1 // Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <openssl/dh.h>
16 
17 #include <assert.h>
18 #include <limits.h>
19 
20 #include <openssl/bn.h>
21 #include <openssl/bytestring.h>
22 #include <openssl/err.h>
23 
24 #include "../bytestring/internal.h"
25 #include "../fipsmodule/dh/internal.h"
26 
27 
parse_integer(CBS * cbs,BIGNUM ** out)28 static int parse_integer(CBS *cbs, BIGNUM **out) {
29   assert(*out == NULL);
30   *out = BN_new();
31   if (*out == NULL) {
32     return 0;
33   }
34   return BN_parse_asn1_unsigned(cbs, *out);
35 }
36 
marshal_integer(CBB * cbb,BIGNUM * bn)37 static int marshal_integer(CBB *cbb, BIGNUM *bn) {
38   if (bn == NULL) {
39     // A DH object may be missing some components.
40     OPENSSL_PUT_ERROR(DH, ERR_R_PASSED_NULL_PARAMETER);
41     return 0;
42   }
43   return BN_marshal_asn1(cbb, bn);
44 }
45 
DH_parse_parameters(CBS * cbs)46 DH *DH_parse_parameters(CBS *cbs) {
47   bssl::UniquePtr<DH> ret(DH_new());
48   if (ret == nullptr) {
49     return nullptr;
50   }
51 
52   CBS child;
53   if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
54       !parse_integer(&child, &ret->p) ||
55       !parse_integer(&child, &ret->g)) {
56     OPENSSL_PUT_ERROR(DH, DH_R_DECODE_ERROR);
57     return nullptr;
58   }
59 
60   uint64_t priv_length;
61   if (CBS_len(&child) != 0) {
62     if (!CBS_get_asn1_uint64(&child, &priv_length) ||
63         priv_length > UINT_MAX) {
64       OPENSSL_PUT_ERROR(DH, DH_R_DECODE_ERROR);
65       return nullptr;
66     }
67     ret->priv_length = (unsigned)priv_length;
68   }
69 
70   if (CBS_len(&child) != 0) {
71     OPENSSL_PUT_ERROR(DH, DH_R_DECODE_ERROR);
72     return nullptr;
73   }
74 
75   if (!dh_check_params_fast(ret.get())) {
76     OPENSSL_PUT_ERROR(DH, DH_R_DECODE_ERROR);
77     return nullptr;
78   }
79 
80   return ret.release();
81 }
82 
DH_marshal_parameters(CBB * cbb,const DH * dh)83 int DH_marshal_parameters(CBB *cbb, const DH *dh) {
84   CBB child;
85   if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
86       !marshal_integer(&child, dh->p) ||
87       !marshal_integer(&child, dh->g) ||
88       (dh->priv_length != 0 &&
89        !CBB_add_asn1_uint64(&child, dh->priv_length)) ||
90       !CBB_flush(cbb)) {
91     OPENSSL_PUT_ERROR(DH, DH_R_ENCODE_ERROR);
92     return 0;
93   }
94   return 1;
95 }
96 
d2i_DHparams(DH ** out,const uint8_t ** inp,long len)97 DH *d2i_DHparams(DH **out, const uint8_t **inp, long len) {
98   if (len < 0) {
99     return NULL;
100   }
101   CBS cbs;
102   CBS_init(&cbs, *inp, (size_t)len);
103   DH *ret = DH_parse_parameters(&cbs);
104   if (ret == NULL) {
105     return NULL;
106   }
107   if (out != NULL) {
108     DH_free(*out);
109     *out = ret;
110   }
111   *inp = CBS_data(&cbs);
112   return ret;
113 }
114 
i2d_DHparams(const DH * in,uint8_t ** outp)115 int i2d_DHparams(const DH *in, uint8_t **outp) {
116   CBB cbb;
117   if (!CBB_init(&cbb, 0) ||
118       !DH_marshal_parameters(&cbb, in)) {
119     CBB_cleanup(&cbb);
120     return -1;
121   }
122   return CBB_finish_i2d(&cbb, outp);
123 }
124