VirtualBox

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

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

IPRT/ssl: avoid asserting in RTFileExists. bugref:9246

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 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 if (SSL_CTX_get_min_proto_version(pThis->pCtx) < TLS1_VERSION)
114 SSL_CTX_set_min_proto_version(pThis->pCtx, TLS1_VERSION);
115# elif OPENSSL_VERSION_NUMBER >= 0x10002000
116 SSL_CTX_set_options(pThis->pCtx, SSL_OP_NO_SSLv2);
117 SSL_CTX_set_options(pThis->pCtx, SSL_OP_NO_SSLv3);
118# endif
119
120 /*
121 * Complete the instance and return it.
122 */
123 pThis->u32Magic = RTCRSSLINT_MAGIC;
124 pThis->cRefs = 1;
125
126 *phSsl = pThis;
127 return VINF_SUCCESS;
128 }
129 }
130 return VERR_NO_MEMORY;
131 }
132 return VERR_NOT_SUPPORTED;
133}
134
135
136RTDECL(uint32_t) RTCrSslRetain(RTCRSSL hSsl)
137{
138 RTCRSSLINT *pThis = hSsl;
139 AssertPtrReturn(pThis, UINT32_MAX);
140 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, UINT32_MAX);
141
142 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
143 Assert(cRefs > 1);
144 Assert(cRefs < 1024);
145 return cRefs;
146}
147
148
149/**
150 * Worker for RTCrSslRelease.
151 */
152static int rtCrSslDestroy(RTCRSSLINT *pThis)
153{
154 ASMAtomicWriteU32(&pThis->u32Magic, ~RTCRSSLINT_MAGIC);
155 SSL_CTX_free(pThis->pCtx);
156 pThis->pCtx = NULL;
157 RTMemFree(pThis);
158 return 0;
159}
160
161
162RTDECL(uint32_t) RTCrSslRelease(RTCRSSL hSsl)
163{
164 RTCRSSLINT *pThis = hSsl;
165 if (pThis == NIL_RTCRSSL)
166 return 0;
167 AssertPtrReturn(pThis, UINT32_MAX);
168 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, UINT32_MAX);
169
170 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
171 Assert(cRefs < 1024);
172 if (cRefs == 0)
173 return rtCrSslDestroy(pThis);
174 return cRefs;
175}
176
177
178RTDECL(int) RTCrSslSetCertificateFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags)
179{
180 RTCRSSLINT *pThis = hSsl;
181 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
182 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
183 AssertReturn(!(fFlags & ~RTCRSSL_FILE_F_ASN1), VERR_INVALID_FLAGS);
184
185 int rcOssl = SSL_CTX_use_certificate_file(pThis->pCtx, pszFile,
186 RTCRSSL_FILE_F_ASN1 & fFlags ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM);
187 if (rcOssl != 0)
188 return VINF_SUCCESS;
189 return !pszFile || !*pszFile || !RTFileExists(pszFile) ? VERR_FILE_NOT_FOUND : VERR_OPEN_FAILED; /** @todo Better status codes */
190}
191
192
193RTDECL(int) RTCrSslSetPrivateKeyFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags)
194{
195 RTCRSSLINT *pThis = hSsl;
196 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
197 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
198 AssertReturn(!(fFlags & ~RTCRSSL_FILE_F_ASN1), VERR_INVALID_FLAGS);
199
200 int rcOssl = SSL_CTX_use_PrivateKey_file(pThis->pCtx, pszFile,
201 RTCRSSL_FILE_F_ASN1 & fFlags ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM);
202 if (rcOssl != 0)
203 return VINF_SUCCESS;
204 return !pszFile || !*pszFile || !RTFileExists(pszFile) ? VERR_FILE_NOT_FOUND : VERR_OPEN_FAILED; /** @todo Better status codes */
205}
206
207
208RTDECL(int) RTCrSslLoadTrustedRootCerts(RTCRSSL hSsl, const char *pszFile, const char *pszDir)
209{
210 RTCRSSLINT *pThis = hSsl;
211 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
212 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
213
214 int rcOssl = SSL_CTX_load_verify_locations(pThis->pCtx, pszFile, pszDir);
215 if (rcOssl != 0)
216 return VINF_SUCCESS;
217
218 if (!pszFile || !*pszFile || !RTFileExists(pszFile))
219 return VERR_FILE_NOT_FOUND;
220 return VERR_OPEN_FAILED; /** @todo Better status codes */
221}
222
223
224RTDECL(int) RTCrSslSetNoPeerVerify(RTCRSSL hSsl)
225{
226 RTCRSSLINT *pThis = hSsl;
227 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
228 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
229
230 SSL_CTX_set_verify(pThis->pCtx, SSL_VERIFY_NONE, NULL);
231 return VINF_SUCCESS;
232}
233
234
235
236//RTDECL(int) RTCrSslCreateSession(RTCRSSL hSsl, RTSOCKET hSocket, uint32_t fFlags, PRTCRSSLSESSION phSslConn);
237
238RTDECL(int) RTCrSslCreateSessionForNativeSocket(RTCRSSL hSsl, RTHCINTPTR hNativeSocket, uint32_t fFlags,
239 PRTCRSSLSESSION phSslSession)
240{
241 /*
242 * Validate input.
243 */
244 *phSslSession = NIL_RTCRSSLSESSION;
245
246 RTCRSSLINT *pThis = hSsl;
247 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
248 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
249 AssertReturn(!(fFlags & ~RTCRSSLSESSION_F_NON_BLOCKING), VERR_INVALID_FLAGS);
250
251 /*
252 * Create a new session.
253 */
254 int rc = VERR_NO_MEMORY;
255 RTCRSSLSESSIONINT *pSession = (RTCRSSLSESSIONINT *)RTMemAllocZ(sizeof(*pSession));
256 if (pSession)
257 {
258 pSession->pSsl = SSL_new(pThis->pCtx);
259 if (pSession->pSsl)
260 {
261 /* Disable read-ahead if non-blocking socket relying on select/poll. */
262 if (fFlags & RTCRSSLSESSION_F_NON_BLOCKING)
263 SSL_set_read_ahead(pSession->pSsl, 0);
264
265 /* Create a wrapper for the socket handle. */
266 pSession->pBio = BIO_new_socket(hNativeSocket, BIO_NOCLOSE);
267 if (pSession->pBio)
268 {
269# if OPENSSL_VERSION_NUMBER >= 0x10100000
270 BIO_up_ref(pSession->pBio); /* our reference. */
271# endif
272 SSL_set_bio(pSession->pSsl, pSession->pBio, pSession->pBio);
273
274 /*
275 * Done.
276 */
277 pSession->cRefs = 1;
278 pSession->u32Magic = RTCRSSLSESSIONINT_MAGIC;
279 *phSslSession = pSession;
280 return VINF_SUCCESS;
281 }
282
283 SSL_free(pSession->pSsl);
284 pSession->pSsl = NULL;
285 }
286 RTMemFree(pThis);
287 }
288 return rc;
289}
290
291
292/*********************************************************************************************************************************
293* Session implementation. *
294*********************************************************************************************************************************/
295
296RTDECL(uint32_t) RTCrSslSessionRetain(RTCRSSLSESSION hSslSession)
297{
298 RTCRSSLSESSIONINT *pThis = hSslSession;
299 AssertPtrReturn(pThis, UINT32_MAX);
300 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, UINT32_MAX);
301
302 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
303 Assert(cRefs > 1);
304 Assert(cRefs < 1024);
305 return cRefs;
306}
307
308
309/**
310 * Worker for RTCrSslRelease.
311 */
312static int rtCrSslSessionDestroy(RTCRSSLSESSIONINT *pThis)
313{
314 ASMAtomicWriteU32(&pThis->u32Magic, ~RTCRSSLSESSIONINT_MAGIC);
315 SSL_free(pThis->pSsl);
316 pThis->pSsl = NULL;
317# if OPENSSL_VERSION_NUMBER >= 0x10100000
318 BIO_free(pThis->pBio);
319# endif
320 pThis->pBio = NULL;
321 RTMemFree(pThis);
322 return 0;
323}
324
325
326RTDECL(uint32_t) RTCrSslSessionRelease(RTCRSSLSESSION hSslSession)
327{
328 RTCRSSLSESSIONINT *pThis = hSslSession;
329 if (pThis == NIL_RTCRSSLSESSION)
330 return 0;
331 AssertPtrReturn(pThis, UINT32_MAX);
332 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, UINT32_MAX);
333
334 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
335 Assert(cRefs < 1024);
336 if (cRefs == 0)
337 return rtCrSslSessionDestroy(pThis);
338 return cRefs;
339}
340
341
342RTDECL(int) RTCrSslSessionAccept(RTCRSSLSESSION hSslSession, uint32_t fFlags)
343{
344 RTCRSSLSESSIONINT *pThis = hSslSession;
345 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
346 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
347 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
348
349 int rcOssl = SSL_accept(pThis->pSsl);
350 if (rcOssl > 0)
351 return VINF_SUCCESS;
352
353 /** @todo better status codes. */
354 if (BIO_should_retry(pThis->pBio))
355 return VERR_TRY_AGAIN;
356 return VERR_NOT_SUPPORTED;
357}
358
359
360RTDECL(int) RTCrSslSessionConnect(RTCRSSLSESSION hSslSession, uint32_t fFlags)
361{
362 RTCRSSLSESSIONINT *pThis = hSslSession;
363 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
364 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
365 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
366
367 int rcOssl = SSL_connect(pThis->pSsl);
368 if (rcOssl > 0)
369 return VINF_SUCCESS;
370
371 /** @todo better status codes. */
372 if (BIO_should_retry(pThis->pBio))
373 return VERR_TRY_AGAIN;
374 return VERR_NOT_SUPPORTED;
375}
376
377
378RTDECL(const char *) RTCrSslSessionGetVersion(RTCRSSLSESSION hSslSession)
379{
380 RTCRSSLSESSIONINT *pThis = hSslSession;
381 AssertPtrReturn(pThis, NULL);
382 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, NULL);
383
384 return SSL_get_version(pThis->pSsl);
385}
386
387
388RTDECL(int) RTCrSslSessionGetCertIssuerNameAsString(RTCRSSLSESSION hSslSession, char *pszBuf, size_t cbBuf, size_t *pcbActual)
389{
390 RTCRSSLSESSIONINT *pThis = hSslSession;
391 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
392 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
393 AssertPtrNull(pszBuf);
394 AssertPtrNull(pcbActual);
395 if (pcbActual)
396 *pcbActual = 0;
397
398 /*
399 * Get and format the certificate issuer name.
400 */
401 int rc = VERR_NOT_AVAILABLE;
402 X509 *pCert = SSL_get_certificate(pThis->pSsl);
403 if (pCert)
404 {
405 X509_NAME *pIssuer = X509_get_issuer_name(pCert);
406 if (pIssuer)
407 {
408 char *pszSrc = X509_NAME_oneline(pIssuer, NULL, 0);
409 if (pszSrc)
410 {
411 /*
412 * Copy out the result and free it.
413 */
414 size_t cbNeeded = strlen(pszSrc) + 1;
415 if (pcbActual)
416 *pcbActual = cbNeeded;
417
418 if (pszBuf != NULL && cbBuf > 0)
419 {
420 if (cbBuf >= cbNeeded)
421 {
422 memcpy(pszBuf, pszSrc, cbNeeded);
423 rc = VINF_SUCCESS;
424 }
425 else
426 {
427 memcpy(pszBuf, pszSrc, cbBuf - 1);
428 pszBuf[cbBuf - 1] = '\0';
429 rc = VERR_BUFFER_OVERFLOW;
430 }
431 }
432 else
433 rc = VERR_BUFFER_OVERFLOW;
434 OPENSSL_free(pszSrc);
435 }
436 }
437 }
438 return rc;
439}
440
441
442RTDECL(bool) RTCrSslSessionPending(RTCRSSLSESSION hSslSession)
443{
444 RTCRSSLSESSIONINT *pThis = hSslSession;
445 AssertPtrReturn(pThis, true);
446 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, true);
447
448 return SSL_pending(pThis->pSsl) != 0;
449}
450
451
452RTDECL(ssize_t) RTCrSslSessionRead(RTCRSSLSESSION hSslSession, void *pvBuf, size_t cbToRead)
453{
454 RTCRSSLSESSIONINT *pThis = hSslSession;
455 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
456 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
457
458 Assert((size_t)(int)cbToRead == cbToRead);
459
460 int cbActual = SSL_read(pThis->pSsl, pvBuf, (int)cbToRead);
461 if (cbActual > 0)
462 return cbActual;
463 if (BIO_should_retry(pThis->pBio))
464 return VERR_TRY_AGAIN;
465 return VERR_READ_ERROR; /** @todo better status codes. */
466}
467
468
469RTDECL(ssize_t) RTCrSslSessionWrite(RTCRSSLSESSION hSslSession, void const *pvBuf, size_t cbToWrite)
470{
471 RTCRSSLSESSIONINT *pThis = hSslSession;
472 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
473 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
474
475 Assert((size_t)(int)cbToWrite == cbToWrite);
476 Assert(cbToWrite != 0 /* undefined behavior if zero */);
477
478 int cbActual = SSL_write(pThis->pSsl, pvBuf, (int)cbToWrite);
479 if (cbActual > 0)
480 return cbActual;
481 if (BIO_should_retry(pThis->pBio))
482 return VERR_TRY_AGAIN;
483 return VERR_WRITE_ERROR; /** @todo better status codes. */
484}
485
486#endif /* IPRT_WITH_OPENSSL */
487
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