1 #include <assert.h>
2 #include <stddef.h>
3 
4 #include <openssl/bn.h>
5 #include <openssl/err.h>
6 #include <openssl/opensslv.h>
7 #include <openssl/rsa.h>
8 
9 #include "warnp.h"
10 
11 #include "crypto_compat.h"
12 
13 #ifndef OPENSSL_VERSION_NUMBER
14 #error "OPENSSL_VERSION_NUMBER must be defined"
15 #endif
16 
17 /*
18  * LibreSSL claims to be OpenSSL 2.0, but (currently) has APIs compatible with
19  * OpenSSL 1.0.1g.
20  */
21 #ifdef LIBRESSL_VERSION_NUMBER
22 #undef OPENSSL_VERSION_NUMBER
23 #define OPENSSL_VERSION_NUMBER 0x1000107fL
24 #endif
25 
26 /**
27  * crypto_compat_RSA_valid_size(rsa):
28  * Return nonzero if ${rsa} has a valid size, and zero for an invalid size.
29  */
30 int
crypto_compat_RSA_valid_size(const RSA * const rsa)31 crypto_compat_RSA_valid_size(const RSA * const rsa)
32 {
33 
34 	/* Sanity checks. */
35 	assert(rsa != NULL);
36 
37 #if OPENSSL_VERSION_NUMBER < 0x10100000L
38 	assert(rsa->n != NULL);
39 	return ((RSA_size(rsa) == 256) && (BN_num_bits(rsa->n) == 2048));
40 #else
41 	return ((RSA_size(rsa) == 256) && (RSA_bits(rsa) == 2048));
42 #endif
43 }
44 
45 /**
46  * crypto_compat_RSA_import(key, n, e, d, p, q, dmp1, dmq1, iqmp):
47  * Import the given BIGNUMs into the RSA ${key}.
48  */
49 int
crypto_compat_RSA_import(RSA ** key,BIGNUM * n,BIGNUM * e,BIGNUM * d,BIGNUM * p,BIGNUM * q,BIGNUM * dmp1,BIGNUM * dmq1,BIGNUM * iqmp)50 crypto_compat_RSA_import(RSA ** key, BIGNUM * n, BIGNUM * e, BIGNUM * d,
51     BIGNUM * p, BIGNUM * q, BIGNUM * dmp1, BIGNUM * dmq1, BIGNUM * iqmp)
52 {
53 
54 	/* Sanity checks. */
55 	assert(key != NULL);
56 	assert((n != NULL) && (e != NULL));
57 
58 	/* All the private-key-related variables are NULL, or they're not. */
59 	if (d == NULL) {
60 		assert((p == NULL) && (q == NULL) && (dmp1 == NULL)
61 		    && (dmq1 == NULL) && (iqmp == NULL));
62 	} else {
63 		assert((p != NULL) && (q != NULL) && (dmp1 != NULL)
64 		    && (dmq1 != NULL) && (iqmp != NULL));
65 	}
66 
67 	/* Put values into RSA key. */
68 #if OPENSSL_VERSION_NUMBER < 0x10100000L
69 	(*key)->n = n;
70 	(*key)->e = e;
71 	if (d != NULL) {
72 		/* Private key. */
73 		(*key)->d = d;
74 		(*key)->p = p;
75 		(*key)->q = q;
76 		(*key)->dmp1 = dmp1;
77 		(*key)->dmq1 = dmq1;
78 		(*key)->iqmp = iqmp;
79 	}
80 #else
81 	/* Do we have a public key, or private key? */
82 	if (d == NULL) {
83 		/* We could use d here, but using NULL makes it more clear. */
84 		if (RSA_set0_key(*key, n, e, NULL) != 1)
85 			goto err0;
86 	} else {
87 		/* Private key. */
88 		if (RSA_set0_key(*key, n, e, d) != 1)
89 			goto err0;
90 		if (RSA_set0_factors(*key, p, q) != 1)
91 			goto err0;
92 		if (RSA_set0_crt_params(*key, dmp1, dmq1, iqmp) != 1)
93 			goto err0;
94 	}
95 #endif
96 
97 	/* Success! */
98 	return (0);
99 
100 #if OPENSSL_VERSION_NUMBER < 0x10100000L
101 #else
102 err0:
103 	/* Failure! */
104 	return (-1);
105 #endif
106 }
107 
108 /**
109  * crypto_compat_RSA_export(key, n, e, d, p, q, dmp1, dmq1, iqmp):
110  * Export values from the given RSA ${key} into the BIGNUMs.  ${n} and ${e}
111  * must be non-NULL; the other values may be NULL if desired, and will
112  * therefore not be exported.
113  */
114 int
crypto_compat_RSA_export(RSA * key,const BIGNUM ** n,const BIGNUM ** e,const BIGNUM ** d,const BIGNUM ** p,const BIGNUM ** q,const BIGNUM ** dmp1,const BIGNUM ** dmq1,const BIGNUM ** iqmp)115 crypto_compat_RSA_export(RSA * key, const BIGNUM ** n, const BIGNUM ** e,
116     const BIGNUM ** d, const BIGNUM ** p, const BIGNUM ** q,
117     const BIGNUM ** dmp1, const BIGNUM ** dmq1, const BIGNUM ** iqmp)
118 {
119 
120 	/* Sanity checks. */
121 	assert(key != NULL);
122 	assert((n != NULL) && (e != NULL));
123 
124 	/* All the private-key-related variables are NULL, or they're not. */
125 	if (d == NULL) {
126 		assert((p == NULL) && (q == NULL) && (dmp1 == NULL)
127 		    && (dmq1 == NULL) && (iqmp == NULL));
128 	} else {
129 		assert((p != NULL) && (q != NULL) && (dmp1 != NULL)
130 		    && (dmq1 != NULL) && (iqmp != NULL));
131 	}
132 
133 	/* Get values from RSA key. */
134 #if OPENSSL_VERSION_NUMBER < 0x10100000L
135 	*n = key->n;
136 	*e = key->e;
137 	if (d != NULL) {
138 		/* Private key. */
139 		*d = key->d;
140 		*p = key->p;
141 		*q = key->q;
142 		*dmp1 = key->dmp1;
143 		*dmq1 = key->dmq1;
144 		*iqmp = key->iqmp;
145 	}
146 #else
147 	/* Do we have a public key, or private key? */
148 	if (d == NULL) {
149 		/* We could use d here, but using NULL makes it more clear. */
150 		RSA_get0_key(key, n, e, NULL);
151 	} else {
152 		/* Private key. */
153 		RSA_get0_key(key, n, e, d);
154 		RSA_get0_factors(key, p, q);
155 		RSA_get0_crt_params(key, dmp1, dmq1, iqmp);
156 	}
157 #endif
158 
159 	/* Success! */
160 	return (0);
161 }
162 
163 /**
164  * crypto_compat_RSA_generate_key():
165  * Generate a key pair.
166  */
167 RSA *
crypto_compat_RSA_generate_key()168 crypto_compat_RSA_generate_key()
169 {
170 	RSA * key;
171 
172 #if OPENSSL_VERSION_NUMBER < 0x00908000L
173 	/* Generate key. */
174 	if ((key = RSA_generate_key(2048, 65537, NULL, NULL)) == NULL) {
175 		warn0("%s", ERR_error_string(ERR_get_error(), NULL));
176 		goto err0;
177 	}
178 
179 	/* Success! */
180 	return (key);
181 #else
182 	BIGNUM * e;
183 
184 	/* Set up parameter. */
185 	if ((e = BN_new()) == NULL) {
186 		warn0("%s", ERR_error_string(ERR_get_error(), NULL));
187 		goto err0;
188 	}
189 	BN_set_word(e, 65537);
190 
191 	/* Generate key. */
192 	if ((key = RSA_new()) == NULL) {
193 		warn0("%s", ERR_error_string(ERR_get_error(), NULL));
194 		goto err1;
195 	}
196 	if (RSA_generate_key_ex(key, 2048, e, NULL) != 1) {
197 		warn0("%s", ERR_error_string(ERR_get_error(), NULL));
198 		goto err2;
199 	}
200 
201 	/* Clean up. */
202 	BN_free(e);
203 
204 	/* Success! */
205 	return (key);
206 
207 err2:
208 	RSA_free(key);
209 err1:
210 	BN_free(e);
211 #endif
212 err0:
213 	/* Failure! */
214 	return (NULL);
215 }
216