VirtualBox

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

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

IPRT/ssl: deal with relatively old OpenSSL 1.1.0 releases which don't have the SSL_CTX protocol version getters.

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