VirtualBox

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

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

IPRT/crypto: Wrapped SSL, alleged RC4, and RSA key generation. Added methods for quering someRSA key components. Exposed big numbers, x509 and asn1 APIs as stable. bugref:9246 [openssl 0.98.x build fix]

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