1/*
2 * Copyright 2016-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <folly/portability/OpenSSL.h>
17#include <folly/ssl/detail/OpenSSLThreading.h>
18
19#include <stdexcept>
20
21namespace folly {
22namespace portability {
23namespace ssl {
24
25#ifdef OPENSSL_IS_BORINGSSL
26int SSL_CTX_set1_sigalgs_list(SSL_CTX*, const char*) {
27 return 1; // 0 implies error
28}
29
30int TLS1_get_client_version(SSL* s) {
31 // Note that this isn't the client version, and the API to
32 // get this has been hidden. It may be found by parsing the
33 // ClientHello (there is a callback via the SSL_HANDSHAKE struct)
34 return s->version;
35}
36#endif
37
38#if FOLLY_OPENSSL_IS_100
39uint32_t SSL_CIPHER_get_id(const SSL_CIPHER* c) {
40 return c->id;
41}
42
43int TLS1_get_client_version(const SSL* s) {
44 return (s->client_version >> 8) == TLS1_VERSION_MAJOR ? s->client_version : 0;
45}
46#endif
47
48#if FOLLY_OPENSSL_IS_100 || FOLLY_OPENSSL_IS_101
49int X509_get_signature_nid(X509* cert) {
50 return OBJ_obj2nid(cert->sig_alg->algorithm);
51}
52#endif
53
54#if FOLLY_OPENSSL_IS_100 || FOLLY_OPENSSL_IS_101 || FOLLY_OPENSSL_IS_102
55int SSL_CTX_up_ref(SSL_CTX* ctx) {
56 return CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX);
57}
58
59int SSL_SESSION_up_ref(SSL_SESSION* session) {
60 return CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION);
61}
62
63int X509_up_ref(X509* x) {
64 return CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
65}
66
67int X509_STORE_up_ref(X509_STORE* v) {
68 return CRYPTO_add(&v->references, 1, CRYPTO_LOCK_X509_STORE);
69}
70
71int EVP_PKEY_up_ref(EVP_PKEY* evp) {
72 return CRYPTO_add(&evp->references, 1, CRYPTO_LOCK_EVP_PKEY);
73}
74
75void RSA_get0_key(
76 const RSA* r,
77 const BIGNUM** n,
78 const BIGNUM** e,
79 const BIGNUM** d) {
80 if (n != nullptr) {
81 *n = r->n;
82 }
83 if (e != nullptr) {
84 *e = r->e;
85 }
86 if (d != nullptr) {
87 *d = r->d;
88 }
89}
90
91RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey) {
92 if (pkey->type != EVP_PKEY_RSA) {
93 return nullptr;
94 }
95 return pkey->pkey.rsa;
96}
97
98DSA* EVP_PKEY_get0_DSA(EVP_PKEY* pkey) {
99 if (pkey->type != EVP_PKEY_DSA) {
100 return nullptr;
101 }
102 return pkey->pkey.dsa;
103}
104
105DH* EVP_PKEY_get0_DH(EVP_PKEY* pkey) {
106 if (pkey->type != EVP_PKEY_DH) {
107 return nullptr;
108 }
109 return pkey->pkey.dh;
110}
111
112EC_KEY* EVP_PKEY_get0_EC_KEY(EVP_PKEY* pkey) {
113 if (pkey->type != EVP_PKEY_EC) {
114 return nullptr;
115 }
116 return pkey->pkey.ec;
117}
118#endif
119
120#if !FOLLY_OPENSSL_IS_110
121BIO_METHOD* BIO_meth_new(int type, const char* name) {
122 BIO_METHOD* method = (BIO_METHOD*)OPENSSL_malloc(sizeof(BIO_METHOD));
123 if (method == nullptr) {
124 return nullptr;
125 }
126 memset(method, 0, sizeof(BIO_METHOD));
127 method->type = type;
128 method->name = name;
129 return method;
130}
131
132void BIO_meth_free(BIO_METHOD* biom) {
133 OPENSSL_free((void*)biom);
134}
135
136int BIO_meth_set_read(BIO_METHOD* biom, int (*read)(BIO*, char*, int)) {
137 biom->bread = read;
138 return 1;
139}
140
141int BIO_meth_set_write(BIO_METHOD* biom, int (*write)(BIO*, const char*, int)) {
142 biom->bwrite = write;
143 return 1;
144}
145
146int BIO_meth_set_puts(BIO_METHOD* biom, int (*bputs)(BIO*, const char*)) {
147 biom->bputs = bputs;
148 return 1;
149}
150
151int BIO_meth_set_gets(BIO_METHOD* biom, int (*bgets)(BIO*, char*, int)) {
152 biom->bgets = bgets;
153 return 1;
154}
155
156int BIO_meth_set_ctrl(BIO_METHOD* biom, long (*ctrl)(BIO*, int, long, void*)) {
157 biom->ctrl = ctrl;
158 return 1;
159}
160
161int BIO_meth_set_create(BIO_METHOD* biom, int (*create)(BIO*)) {
162 biom->create = create;
163 return 1;
164}
165
166int BIO_meth_set_destroy(BIO_METHOD* biom, int (*destroy)(BIO*)) {
167 biom->destroy = destroy;
168 return 1;
169}
170
171void BIO_set_data(BIO* bio, void* ptr) {
172 bio->ptr = ptr;
173}
174
175void* BIO_get_data(BIO* bio) {
176 return bio->ptr;
177}
178
179void BIO_set_init(BIO* bio, int init) {
180 bio->init = init;
181}
182
183void BIO_set_shutdown(BIO* bio, int shutdown) {
184 bio->shutdown = shutdown;
185}
186
187const SSL_METHOD* TLS_server_method(void) {
188 return TLSv1_2_server_method();
189}
190
191const SSL_METHOD* TLS_client_method(void) {
192 return TLSv1_2_client_method();
193}
194
195const char* SSL_SESSION_get0_hostname(const SSL_SESSION* s) {
196 return s->tlsext_hostname;
197}
198
199unsigned char* ASN1_STRING_get0_data(const ASN1_STRING* x) {
200 return ASN1_STRING_data((ASN1_STRING*)x);
201}
202
203int SSL_SESSION_has_ticket(const SSL_SESSION* s) {
204 return (s->tlsext_ticklen > 0) ? 1 : 0;
205}
206
207unsigned long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION* s) {
208 return s->tlsext_tick_lifetime_hint;
209}
210
211// This is taken from OpenSSL 1.1.0
212int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) {
213 /* If the fields p and g in d are nullptr, the corresponding input
214 * parameters MUST not be nullptr. q may remain nullptr.
215 */
216 if (dh == nullptr || (dh->p == nullptr && p == nullptr) ||
217 (dh->g == nullptr && g == nullptr)) {
218 return 0;
219 }
220
221 if (p != nullptr) {
222 BN_free(dh->p);
223 dh->p = p;
224 }
225 if (q != nullptr) {
226 BN_free(dh->q);
227 dh->q = q;
228 }
229 if (g != nullptr) {
230 BN_free(dh->g);
231 dh->g = g;
232 }
233
234 // In OpenSSL 1.1.0, DH_set0_pqg also sets
235 // dh->length = BN_num_bits(q)
236 // With OpenSSL 1.0.2, the output of openssl dhparam -C 2048 doesn't set
237 // the length field. So as far as the compat lib is concerned, this wrapper
238 // mimics the functionality of OpenSSL 1.0.2
239 // Note: BoringSSL doesn't even have a length field anymore, just something
240 // called 'priv_length'. Let's not mess with that for now.
241
242 return 1;
243}
244
245void DH_get0_pqg(
246 const DH* dh,
247 const BIGNUM** p,
248 const BIGNUM** q,
249 const BIGNUM** g) {
250 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
251 if (p != nullptr) {
252 *p = dh->p;
253 }
254 if (q != nullptr) {
255 *q = dh->q;
256 }
257 if (g != nullptr) {
258 *g = dh->g;
259 }
260}
261
262void DH_get0_key(
263 const DH* dh,
264 const BIGNUM** pub_key,
265 const BIGNUM** priv_key) {
266 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
267 if (pub_key != nullptr) {
268 *pub_key = dh->pub_key;
269 }
270 if (priv_key != nullptr) {
271 *priv_key = dh->priv_key;
272 }
273}
274
275void DSA_get0_pqg(
276 const DSA* dsa,
277 const BIGNUM** p,
278 const BIGNUM** q,
279 const BIGNUM** g) {
280 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
281 if (p != nullptr) {
282 *p = dsa->p;
283 }
284 if (q != nullptr) {
285 *q = dsa->q;
286 }
287 if (g != nullptr) {
288 *g = dsa->g;
289 }
290}
291
292void DSA_get0_key(
293 const DSA* dsa,
294 const BIGNUM** pub_key,
295 const BIGNUM** priv_key) {
296 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
297 if (pub_key != nullptr) {
298 *pub_key = dsa->pub_key;
299 }
300 if (priv_key != nullptr) {
301 *priv_key = dsa->priv_key;
302 }
303}
304
305STACK_OF(X509_OBJECT) * X509_STORE_get0_objects(X509_STORE* store) {
306 return store->objs;
307}
308
309X509* X509_STORE_CTX_get0_cert(X509_STORE_CTX* ctx) {
310 return ctx->cert;
311}
312
313STACK_OF(X509) * X509_STORE_CTX_get0_chain(X509_STORE_CTX* ctx) {
314 return X509_STORE_CTX_get_chain(ctx);
315}
316
317STACK_OF(X509) * X509_STORE_CTX_get0_untrusted(X509_STORE_CTX* ctx) {
318 return ctx->untrusted;
319}
320
321EVP_MD_CTX* EVP_MD_CTX_new() {
322 EVP_MD_CTX* ctx = (EVP_MD_CTX*)OPENSSL_malloc(sizeof(EVP_MD_CTX));
323 if (!ctx) {
324 throw std::runtime_error("Cannot allocate EVP_MD_CTX");
325 }
326 EVP_MD_CTX_init(ctx);
327 return ctx;
328}
329
330void EVP_MD_CTX_free(EVP_MD_CTX* ctx) {
331 if (ctx) {
332 EVP_MD_CTX_cleanup(ctx);
333 OPENSSL_free(ctx);
334 }
335}
336
337HMAC_CTX* HMAC_CTX_new() {
338 HMAC_CTX* ctx = (HMAC_CTX*)OPENSSL_malloc(sizeof(HMAC_CTX));
339 if (!ctx) {
340 throw std::runtime_error("Cannot allocate HMAC_CTX");
341 }
342 HMAC_CTX_init(ctx);
343 return ctx;
344}
345
346void HMAC_CTX_free(HMAC_CTX* ctx) {
347 if (ctx) {
348 HMAC_CTX_cleanup(ctx);
349 OPENSSL_free(ctx);
350 }
351}
352
353bool RSA_set0_key(RSA* r, BIGNUM* n, BIGNUM* e, BIGNUM* d) {
354 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
355 /**
356 * If the fields n and e in r are nullptr, the corresponding input parameters
357 * MUST be non-nullptr for n and e. d may be left NULL (in case only the
358 * public key is used).
359 */
360 if ((r->n == nullptr && n == nullptr) || (r->e == nullptr && e == nullptr)) {
361 return false;
362 }
363 if (n != nullptr) {
364 BN_free(r->n);
365 r->n = n;
366 }
367 if (e != nullptr) {
368 BN_free(r->e);
369 r->e = e;
370 }
371 if (d != nullptr) {
372 BN_free(r->d);
373 r->d = d;
374 }
375 return true;
376}
377
378void RSA_get0_factors(const RSA* r, const BIGNUM** p, const BIGNUM** q) {
379 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
380 if (p != nullptr) {
381 *p = r->p;
382 }
383 if (q != nullptr) {
384 *q = r->q;
385 }
386}
387
388void RSA_get0_crt_params(
389 const RSA* r,
390 const BIGNUM** dmp1,
391 const BIGNUM** dmq1,
392 const BIGNUM** iqmp) {
393 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
394 if (dmp1 != nullptr) {
395 *dmp1 = r->dmp1;
396 }
397 if (dmq1 != nullptr) {
398 *dmq1 = r->dmq1;
399 }
400 if (iqmp != nullptr) {
401 *iqmp = r->iqmp;
402 }
403}
404
405int ECDSA_SIG_set0(ECDSA_SIG* sig, BIGNUM* r, BIGNUM* s) {
406 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
407 if (r == nullptr || s == nullptr) {
408 return 0;
409 }
410 BN_clear_free(sig->r);
411 BN_clear_free(sig->s);
412 sig->r = r;
413 sig->s = s;
414 return 1;
415}
416
417void ECDSA_SIG_get0(
418 const ECDSA_SIG* sig,
419 const BIGNUM** pr,
420 const BIGNUM** ps) {
421 // Based off of https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
422 if (pr != nullptr) {
423 *pr = sig->r;
424 }
425 if (ps != nullptr) {
426 *ps = sig->s;
427 }
428}
429
430/**
431 * Compatibility shim for OpenSSL < 1.1.0.
432 *
433 * For now, options and settings are ignored. We implement the most common
434 * behavior, which is to add all digests, ciphers, and strings.
435 */
436int OPENSSL_init_ssl(uint64_t, const OPENSSL_INIT_SETTINGS*) {
437 // OpenSSL >= 1.1.0 handles initializing the library, adding digests &
438 // ciphers, loading strings. Additionally, OpenSSL >= 1.1.0 uses platform
439 // native threading & mutexes, which means that we should handle setting up
440 // the necessary threading initialization in the compat layer as well.
441 SSL_library_init();
442 OpenSSL_add_all_ciphers();
443 OpenSSL_add_all_digests();
444 OpenSSL_add_all_algorithms();
445
446 SSL_load_error_strings();
447 ERR_load_crypto_strings();
448
449 // The caller should have used SSLContext::setLockTypes() prior to calling
450 // this function.
451 folly::ssl::detail::installThreadingLocks();
452 return 0;
453}
454
455void OPENSSL_cleanup() {
456 folly::ssl::detail::cleanupThreadingLocks();
457 CRYPTO_cleanup_all_ex_data();
458 ERR_free_strings();
459 EVP_cleanup();
460 ERR_clear_error();
461}
462
463const ASN1_INTEGER* X509_REVOKED_get0_serialNumber(const X509_REVOKED* r) {
464 return r->serialNumber;
465}
466
467const ASN1_TIME* X509_REVOKED_get0_revocationDate(const X509_REVOKED* r) {
468 return r->revocationDate;
469}
470
471uint32_t X509_get_extension_flags(X509* x) {
472 return x->ex_flags;
473}
474
475uint32_t X509_get_key_usage(X509* x) {
476 return x->ex_kusage;
477}
478
479uint32_t X509_get_extended_key_usage(X509* x) {
480 return x->ex_xkusage;
481}
482
483int X509_OBJECT_get_type(const X509_OBJECT* obj) {
484 return obj->type;
485}
486
487X509* X509_OBJECT_get0_X509(const X509_OBJECT* obj) {
488 if (obj == nullptr || obj->type != X509_LU_X509) {
489 return nullptr;
490 }
491 return obj->data.x509;
492}
493
494const ASN1_TIME* X509_CRL_get0_lastUpdate(const X509_CRL* crl) {
495 return X509_CRL_get_lastUpdate(crl);
496}
497
498const ASN1_TIME* X509_CRL_get0_nextUpdate(const X509_CRL* crl) {
499 return X509_CRL_get_nextUpdate(crl);
500}
501
502const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x) {
503 return x->cert_info->signature;
504}
505
506#endif // !FOLLY_OPENSSL_IS_110
507} // namespace ssl
508} // namespace portability
509} // namespace folly
510