VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/ssl-openssl.cpp@ 78306

Last change on this file since 78306 was 77270, checked in by vboxsync, 6 years ago

Runtime: Fix compilation with LibreSSL <2.7.0.
BIO_up_ref() was provided since LibreSSL-2.7.0.
When 2.6.x is used we get an error:

src/VBox/Runtime/common/crypto/ssl-openssl.cpp:275:17: error: ‘BIO_up_ref’ was not declared in this scope

BIO_up_ref(pSession->pBio); /* our reference. */
~

See also: https://bugs.gentoo.org/673800
The patch is submitted under MIT license.
Thank you Stefan Strogin for the patch.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.7 KB
Line 
1/** @file
2 * IPRT - Crypto - Secure Socket Layer (SSL) / Transport Security Layer (TLS).
3 */
4
5/*
6 * Copyright (C) 2018-2019 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25#ifdef IPRT_WITH_OPENSSL /* whole file */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31# include "internal/iprt.h"
32# include <iprt/crypto/ssl.h>
33
34# include <iprt/asm.h>
35# include <iprt/assert.h>
36# include <iprt/err.h>
37# include <iprt/file.h>
38# include <iprt/mem.h>
39# include <iprt/string.h>
40
41# include "internal/magics.h"
42
43# include "internal/iprt-openssl.h"
44# include <openssl/ssl.h>
45# include <openssl/tls1.h>
46
47
48/*********************************************************************************************************************************
49* Header Files *
50*********************************************************************************************************************************/
51/**
52 * SSL instance data for OpenSSL.
53 */
54typedef struct RTCRSSLINT
55{
56 /** Magic value (RTCRSSLINT_MAGIC). */
57 uint32_t u32Magic;
58 /** Reference count. */
59 uint32_t volatile cRefs;
60 /** The SSL context. */
61 SSL_CTX *pCtx;
62} RTCRSSLINT;
63
64/**
65 * SSL session instance data for OpenSSL.
66 */
67typedef struct RTCRSSLSESSIONINT
68{
69 /** Magic value (RTCRSSLSESSIONINT_MAGIC). */
70 uint32_t u32Magic;
71 /** Reference count. */
72 uint32_t volatile cRefs;
73 /** RTCRSSLSESSION_F_XXX. */
74 uint32_t fFlags;
75
76 /** The SSL instance. */
77 SSL *pSsl;
78 /** The socket BIO instance. */
79 BIO *pBio;
80} RTCRSSLSESSIONINT;
81
82
83
84RTDECL(int) RTCrSslCreate(PRTCRSSL phSsl, uint32_t fFlags)
85{
86 AssertPtr(phSsl);
87 *phSsl = NIL_RTCRSSL;
88 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
89
90 SSL_library_init();
91
92 /*
93 * We aim at TLSv1 or higher here by default.
94 */
95# if OPENSSL_VERSION_NUMBER >= 0x10100000
96 const SSL_METHOD *pSslMethod = TLS_method();
97# elif OPENSSL_VERSION_NUMBER >= 0x10002000
98 const SSL_METHOD *pSslMethod = SSLv23_method();
99# elif OPENSSL_VERSION_NUMBER >= 0x10000000
100 const SSL_METHOD *pSslMethod = TLSv1_method();
101# else
102 SSL_METHOD *pSslMethod = TLSv1_method();
103# endif
104 if (pSslMethod)
105 {
106 RTCRSSLINT *pThis = (RTCRSSLINT *)RTMemAllocZ(sizeof(*pThis));
107 if (pThis)
108 {
109 pThis->pCtx = SSL_CTX_new(pSslMethod);
110 if (pThis->pCtx)
111 {
112 /* Help with above aim. */
113# if OPENSSL_VERSION_NUMBER >= 0x10100000
114# ifndef SSL_CTX_get_min_proto_version
115/* Some older OpenSSL 1.1.0 releases lack the getters, officially they were
116 * added with 1.1.1 but someone cherry picked them, just maybe too late. */
117# define SSL_CTX_get_min_proto_version(ctx) (0)
118# endif
119 if (SSL_CTX_get_min_proto_version(pThis->pCtx) < TLS1_VERSION)
120 SSL_CTX_set_min_proto_version(pThis->pCtx, TLS1_VERSION);
121# elif OPENSSL_VERSION_NUMBER >= 0x10002000
122 SSL_CTX_set_options(pThis->pCtx, SSL_OP_NO_SSLv2);
123 SSL_CTX_set_options(pThis->pCtx, SSL_OP_NO_SSLv3);
124# endif
125
126 /*
127 * Complete the instance and return it.
128 */
129 pThis->u32Magic = RTCRSSLINT_MAGIC;
130 pThis->cRefs = 1;
131
132 *phSsl = pThis;
133 return VINF_SUCCESS;
134 }
135 }
136 return VERR_NO_MEMORY;
137 }
138 return VERR_NOT_SUPPORTED;
139}
140
141
142RTDECL(uint32_t) RTCrSslRetain(RTCRSSL hSsl)
143{
144 RTCRSSLINT *pThis = hSsl;
145 AssertPtrReturn(pThis, UINT32_MAX);
146 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, UINT32_MAX);
147
148 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
149 Assert(cRefs > 1);
150 Assert(cRefs < 1024);
151 return cRefs;
152}
153
154
155/**
156 * Worker for RTCrSslRelease.
157 */
158static int rtCrSslDestroy(RTCRSSLINT *pThis)
159{
160 ASMAtomicWriteU32(&pThis->u32Magic, ~RTCRSSLINT_MAGIC);
161 SSL_CTX_free(pThis->pCtx);
162 pThis->pCtx = NULL;
163 RTMemFree(pThis);
164 return 0;
165}
166
167
168RTDECL(uint32_t) RTCrSslRelease(RTCRSSL hSsl)
169{
170 RTCRSSLINT *pThis = hSsl;
171 if (pThis == NIL_RTCRSSL)
172 return 0;
173 AssertPtrReturn(pThis, UINT32_MAX);
174 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, UINT32_MAX);
175
176 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
177 Assert(cRefs < 1024);
178 if (cRefs == 0)
179 return rtCrSslDestroy(pThis);
180 return cRefs;
181}
182
183
184RTDECL(int) RTCrSslSetCertificateFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags)
185{
186 RTCRSSLINT *pThis = hSsl;
187 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
188 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
189 AssertReturn(!(fFlags & ~RTCRSSL_FILE_F_ASN1), VERR_INVALID_FLAGS);
190
191 int rcOssl = SSL_CTX_use_certificate_file(pThis->pCtx, pszFile,
192 RTCRSSL_FILE_F_ASN1 & fFlags ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM);
193 if (rcOssl != 0)
194 return VINF_SUCCESS;
195 return !pszFile || !*pszFile || !RTFileExists(pszFile) ? VERR_FILE_NOT_FOUND : VERR_OPEN_FAILED; /** @todo Better status codes */
196}
197
198
199RTDECL(int) RTCrSslSetPrivateKeyFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags)
200{
201 RTCRSSLINT *pThis = hSsl;
202 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
203 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
204 AssertReturn(!(fFlags & ~RTCRSSL_FILE_F_ASN1), VERR_INVALID_FLAGS);
205
206 int rcOssl = SSL_CTX_use_PrivateKey_file(pThis->pCtx, pszFile,
207 RTCRSSL_FILE_F_ASN1 & fFlags ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM);
208 if (rcOssl != 0)
209 return VINF_SUCCESS;
210 return !pszFile || !*pszFile || !RTFileExists(pszFile) ? VERR_FILE_NOT_FOUND : VERR_OPEN_FAILED; /** @todo Better status codes */
211}
212
213
214RTDECL(int) RTCrSslLoadTrustedRootCerts(RTCRSSL hSsl, const char *pszFile, const char *pszDir)
215{
216 RTCRSSLINT *pThis = hSsl;
217 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
218 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
219
220 int rcOssl = SSL_CTX_load_verify_locations(pThis->pCtx, pszFile, pszDir);
221 if (rcOssl != 0)
222 return VINF_SUCCESS;
223
224 if (!pszFile || !*pszFile || !RTFileExists(pszFile))
225 return VERR_FILE_NOT_FOUND;
226 return VERR_OPEN_FAILED; /** @todo Better status codes */
227}
228
229
230RTDECL(int) RTCrSslSetNoPeerVerify(RTCRSSL hSsl)
231{
232 RTCRSSLINT *pThis = hSsl;
233 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
234 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
235
236 SSL_CTX_set_verify(pThis->pCtx, SSL_VERIFY_NONE, NULL);
237 return VINF_SUCCESS;
238}
239
240
241
242//RTDECL(int) RTCrSslCreateSession(RTCRSSL hSsl, RTSOCKET hSocket, uint32_t fFlags, PRTCRSSLSESSION phSslConn);
243
244RTDECL(int) RTCrSslCreateSessionForNativeSocket(RTCRSSL hSsl, RTHCINTPTR hNativeSocket, uint32_t fFlags,
245 PRTCRSSLSESSION phSslSession)
246{
247 /*
248 * Validate input.
249 */
250 *phSslSession = NIL_RTCRSSLSESSION;
251
252 RTCRSSLINT *pThis = hSsl;
253 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
254 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
255 AssertReturn(!(fFlags & ~RTCRSSLSESSION_F_NON_BLOCKING), VERR_INVALID_FLAGS);
256
257 /*
258 * Create a new session.
259 */
260 int rc = VERR_NO_MEMORY;
261 RTCRSSLSESSIONINT *pSession = (RTCRSSLSESSIONINT *)RTMemAllocZ(sizeof(*pSession));
262 if (pSession)
263 {
264 pSession->pSsl = SSL_new(pThis->pCtx);
265 if (pSession->pSsl)
266 {
267 /* Disable read-ahead if non-blocking socket relying on select/poll. */
268 if (fFlags & RTCRSSLSESSION_F_NON_BLOCKING)
269 SSL_set_read_ahead(pSession->pSsl, 0);
270
271 /* Create a wrapper for the socket handle. */
272 pSession->pBio = BIO_new_socket(hNativeSocket, BIO_NOCLOSE);
273 if (pSession->pBio)
274 {
275# if (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)) || LIBRESSL_VERSION_NUMBER >= 0x2070000f
276 BIO_up_ref(pSession->pBio); /* our reference. */
277# endif
278 SSL_set_bio(pSession->pSsl, pSession->pBio, pSession->pBio);
279
280 /*
281 * Done.
282 */
283 pSession->cRefs = 1;
284 pSession->u32Magic = RTCRSSLSESSIONINT_MAGIC;
285 *phSslSession = pSession;
286 return VINF_SUCCESS;
287 }
288
289 SSL_free(pSession->pSsl);
290 pSession->pSsl = NULL;
291 }
292 RTMemFree(pThis);
293 }
294 return rc;
295}
296
297
298/*********************************************************************************************************************************
299* Session implementation. *
300*********************************************************************************************************************************/
301
302RTDECL(uint32_t) RTCrSslSessionRetain(RTCRSSLSESSION hSslSession)
303{
304 RTCRSSLSESSIONINT *pThis = hSslSession;
305 AssertPtrReturn(pThis, UINT32_MAX);
306 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, UINT32_MAX);
307
308 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
309 Assert(cRefs > 1);
310 Assert(cRefs < 1024);
311 return cRefs;
312}
313
314
315/**
316 * Worker for RTCrSslRelease.
317 */
318static int rtCrSslSessionDestroy(RTCRSSLSESSIONINT *pThis)
319{
320 ASMAtomicWriteU32(&pThis->u32Magic, ~RTCRSSLSESSIONINT_MAGIC);
321 SSL_free(pThis->pSsl);
322 pThis->pSsl = NULL;
323# if (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)) || LIBRESSL_VERSION_NUMBER >= 0x2070000f
324 BIO_free(pThis->pBio);
325# endif
326 pThis->pBio = NULL;
327 RTMemFree(pThis);
328 return 0;
329}
330
331
332RTDECL(uint32_t) RTCrSslSessionRelease(RTCRSSLSESSION hSslSession)
333{
334 RTCRSSLSESSIONINT *pThis = hSslSession;
335 if (pThis == NIL_RTCRSSLSESSION)
336 return 0;
337 AssertPtrReturn(pThis, UINT32_MAX);
338 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, UINT32_MAX);
339
340 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
341 Assert(cRefs < 1024);
342 if (cRefs == 0)
343 return rtCrSslSessionDestroy(pThis);
344 return cRefs;
345}
346
347
348RTDECL(int) RTCrSslSessionAccept(RTCRSSLSESSION hSslSession, uint32_t fFlags)
349{
350 RTCRSSLSESSIONINT *pThis = hSslSession;
351 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
352 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
353 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
354
355 int rcOssl = SSL_accept(pThis->pSsl);
356 if (rcOssl > 0)
357 return VINF_SUCCESS;
358
359 /** @todo better status codes. */
360 if (BIO_should_retry(pThis->pBio))
361 return VERR_TRY_AGAIN;
362 return VERR_NOT_SUPPORTED;
363}
364
365
366RTDECL(int) RTCrSslSessionConnect(RTCRSSLSESSION hSslSession, uint32_t fFlags)
367{
368 RTCRSSLSESSIONINT *pThis = hSslSession;
369 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
370 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
371 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
372
373 int rcOssl = SSL_connect(pThis->pSsl);
374 if (rcOssl > 0)
375 return VINF_SUCCESS;
376
377 /** @todo better status codes. */
378 if (BIO_should_retry(pThis->pBio))
379 return VERR_TRY_AGAIN;
380 return VERR_NOT_SUPPORTED;
381}
382
383
384RTDECL(const char *) RTCrSslSessionGetVersion(RTCRSSLSESSION hSslSession)
385{
386 RTCRSSLSESSIONINT *pThis = hSslSession;
387 AssertPtrReturn(pThis, NULL);
388 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, NULL);
389
390 return SSL_get_version(pThis->pSsl);
391}
392
393
394RTDECL(int) RTCrSslSessionGetCertIssuerNameAsString(RTCRSSLSESSION hSslSession, char *pszBuf, size_t cbBuf, size_t *pcbActual)
395{
396 RTCRSSLSESSIONINT *pThis = hSslSession;
397 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
398 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
399 AssertPtrNull(pszBuf);
400 AssertPtrNull(pcbActual);
401 if (pcbActual)
402 *pcbActual = 0;
403
404 /*
405 * Get and format the certificate issuer name.
406 */
407 int rc = VERR_NOT_AVAILABLE;
408 X509 *pCert = SSL_get_certificate(pThis->pSsl);
409 if (pCert)
410 {
411 X509_NAME *pIssuer = X509_get_issuer_name(pCert);
412 if (pIssuer)
413 {
414 char *pszSrc = X509_NAME_oneline(pIssuer, NULL, 0);
415 if (pszSrc)
416 {
417 /*
418 * Copy out the result and free it.
419 */
420 size_t cbNeeded = strlen(pszSrc) + 1;
421 if (pcbActual)
422 *pcbActual = cbNeeded;
423
424 if (pszBuf != NULL && cbBuf > 0)
425 {
426 if (cbBuf >= cbNeeded)
427 {
428 memcpy(pszBuf, pszSrc, cbNeeded);
429 rc = VINF_SUCCESS;
430 }
431 else
432 {
433 memcpy(pszBuf, pszSrc, cbBuf - 1);
434 pszBuf[cbBuf - 1] = '\0';
435 rc = VERR_BUFFER_OVERFLOW;
436 }
437 }
438 else
439 rc = VERR_BUFFER_OVERFLOW;
440 OPENSSL_free(pszSrc);
441 }
442 }
443 }
444 return rc;
445}
446
447
448RTDECL(bool) RTCrSslSessionPending(RTCRSSLSESSION hSslSession)
449{
450 RTCRSSLSESSIONINT *pThis = hSslSession;
451 AssertPtrReturn(pThis, true);
452 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, true);
453
454 return SSL_pending(pThis->pSsl) != 0;
455}
456
457
458RTDECL(ssize_t) RTCrSslSessionRead(RTCRSSLSESSION hSslSession, void *pvBuf, size_t cbToRead)
459{
460 RTCRSSLSESSIONINT *pThis = hSslSession;
461 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
462 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
463
464 Assert((size_t)(int)cbToRead == cbToRead);
465
466 int cbActual = SSL_read(pThis->pSsl, pvBuf, (int)cbToRead);
467 if (cbActual > 0)
468 return cbActual;
469 if (BIO_should_retry(pThis->pBio))
470 return VERR_TRY_AGAIN;
471 return VERR_READ_ERROR; /** @todo better status codes. */
472}
473
474
475RTDECL(ssize_t) RTCrSslSessionWrite(RTCRSSLSESSION hSslSession, void const *pvBuf, size_t cbToWrite)
476{
477 RTCRSSLSESSIONINT *pThis = hSslSession;
478 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
479 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
480
481 Assert((size_t)(int)cbToWrite == cbToWrite);
482 Assert(cbToWrite != 0 /* undefined behavior if zero */);
483
484 int cbActual = SSL_write(pThis->pSsl, pvBuf, (int)cbToWrite);
485 if (cbActual > 0)
486 return cbActual;
487 if (BIO_should_retry(pThis->pBio))
488 return VERR_TRY_AGAIN;
489 return VERR_WRITE_ERROR; /** @todo better status codes. */
490}
491
492#endif /* IPRT_WITH_OPENSSL */
493
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette