VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/store.cpp@ 84253

Last change on this file since 84253 was 84253, checked in by vboxsync, 5 years ago

IPRT/store: Fixed incorrect check for X.509 DER encoding in the openssl conversion functions. bugref:9699

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 KB
Line 
1/* $Id: store.cpp 84253 2020-05-11 12:29:09Z vboxsync $ */
2/** @file
3 * IPRT - Cryptographic (Certificate) Store.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/crypto/store.h>
33
34#include <iprt/asm.h>
35#include <iprt/err.h>
36#include <iprt/mem.h>
37#include <iprt/string.h>
38
39#include <iprt/crypto/x509.h>
40
41#ifdef IPRT_WITH_OPENSSL
42# include <openssl/x509.h>
43#endif
44
45#include "store-internal.h"
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51/**
52 * Internal representation of a (certificate,++) store.
53 */
54typedef struct RTCRSTOREINT
55{
56 /** Magic number (RTCRSTOREINT_MAGIC). */
57 uint32_t u32Magic;
58 /** Reference counter. */
59 uint32_t volatile cRefs;
60 /** Pointer to the store provider. */
61 PCRTCRSTOREPROVIDER pProvider;
62 /** Provider specific data. */
63 void *pvProvider;
64} RTCRSTOREINT;
65/** Pointer to the internal representation of a store. */
66typedef RTCRSTOREINT *PRTCRSTOREINT;
67
68/** Magic value for RTCRSTOREINT::u32Magic (Alfred Dillwyn "Dilly" Knox). */
69#define RTCRSTOREINT_MAGIC UINT32_C(0x18840723)
70/** Dead magic value for RTCRSTOREINT::u32Magic. */
71#define RTCRSTOREINT_MAGIC_DEAD UINT32_C(0x19430227)
72
73
74
75/**
76 * Internal method a store provider uses to create a store handle.
77 *
78 * @returns IPRT status code
79 * @param pProvider Pointer to the store provider callback table.
80 * @param pvProvider Pointer to the provider specific instance data.
81 * @param phStore Where to return the store handle.
82 */
83DECLHIDDEN(int) rtCrStoreCreate(PCRTCRSTOREPROVIDER pProvider, void *pvProvider, PRTCRSTORE phStore)
84{
85 PRTCRSTOREINT pThis = (PRTCRSTOREINT)RTMemAlloc(sizeof(*pThis));
86 if (pThis)
87 {
88 pThis->pvProvider = pvProvider;
89 pThis->pProvider = pProvider;
90 pThis->cRefs = 1;
91 pThis->u32Magic = RTCRSTOREINT_MAGIC;
92 *phStore = pThis;
93 return VINF_SUCCESS;
94 }
95 return VERR_NO_MEMORY;
96}
97
98
99
100RTDECL(uint32_t) RTCrStoreRetain(RTCRSTORE hStore)
101{
102 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
103 AssertPtrReturn(pThis, UINT32_MAX);
104 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, UINT32_MAX);
105
106 uint32_t cRet = ASMAtomicIncU32(&pThis->cRefs);
107 Assert(cRet < 8192);
108 return cRet;
109}
110
111
112RTDECL(uint32_t) RTCrStoreRelease(RTCRSTORE hStore)
113{
114 if (hStore == NIL_RTCRSTORE)
115 return 0;
116
117 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
118 AssertPtrReturn(pThis, UINT32_MAX);
119 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, UINT32_MAX);
120
121 uint32_t cStore = ASMAtomicDecU32(&pThis->cRefs);
122 if (!cStore)
123 {
124 ASMAtomicWriteU32(&pThis->u32Magic, RTCRSTOREINT_MAGIC_DEAD);
125 pThis->pProvider->pfnDestroyStore(pThis->pvProvider);
126 RTMemFree(pThis);
127 }
128 return cStore;
129}
130
131
132RTDECL(PCRTCRCERTCTX) RTCrStoreCertByIssuerAndSerialNo(RTCRSTORE hStore, PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNo)
133{
134 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
135 AssertPtrReturn(pThis, NULL);
136 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, NULL);
137 AssertPtrReturn(pIssuer, NULL);
138
139 int rc;
140 RTCRSTORECERTSEARCH Search;
141 if (pThis->pProvider->pfnCertFindByIssuerAndSerialNo)
142 rc = pThis->pProvider->pfnCertFindByIssuerAndSerialNo(pThis->pvProvider, pIssuer, pSerialNo, &Search);
143 else
144 rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search);
145
146 PCRTCRCERTCTX pCertCtx = NULL;
147 if (RT_SUCCESS(rc))
148 {
149 for (;;)
150 {
151 pCertCtx = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search);
152 if (!pCertCtx)
153 break;
154
155 if ( pCertCtx->pCert
156 && RTCrX509Certificate_MatchIssuerAndSerialNumber(pCertCtx->pCert, pIssuer, pSerialNo))
157 break;
158 RTCrCertCtxRelease(pCertCtx);
159 }
160
161 pThis->pProvider->pfnCertSearchDestroy(pThis->pvProvider, &Search);
162 }
163 else
164 AssertMsg(rc == VERR_NOT_FOUND, ("%Rrc\n", rc));
165 return pCertCtx;
166}
167
168
169RTDECL(int) RTCrStoreCertAddEncoded(RTCRSTORE hStore, uint32_t fFlags, void const *pvSrc, size_t cbSrc, PRTERRINFO pErrInfo)
170{
171 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
172 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
173 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE);
174 AssertPtrReturn(pvSrc, VERR_INVALID_POINTER);
175 AssertReturn(cbSrc > 16 && cbSrc < _1M, VERR_OUT_OF_RANGE);
176 AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ENC_MASK)), VERR_INVALID_FLAGS);
177 AssertMsgReturn( (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
178 || (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_TAF_DER
179 , ("Only X.509 and TAF DER supported: %#x\n", fFlags), VERR_INVALID_FLAGS);
180
181 int rc;
182 if (pThis->pProvider->pfnCertAddEncoded)
183 rc = pThis->pProvider->pfnCertAddEncoded(pThis->pvProvider, fFlags, (uint8_t const *)pvSrc, (uint32_t)cbSrc, pErrInfo);
184 else
185 rc = VERR_WRITE_PROTECT;
186
187 return rc;
188}
189
190
191
192/*
193 * Searching.
194 * Searching.
195 * Searching.
196 */
197
198RTDECL(int) RTCrStoreCertFindAll(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch)
199{
200 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
201 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
202 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE);
203 AssertPtrReturn(pSearch, VERR_INVALID_POINTER);
204
205 return pThis->pProvider->pfnCertFindAll(pThis->pvProvider, pSearch);
206}
207
208
209/** Indicator for RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280 searches
210 * implemented by this front-end code. */
211#define RTCRSTORECERTSEARCH_BY_SUBECT_OR_ALT_SUBJECT_BY_RFC5280 UINT32_C(0x5be9145d)
212
213RTDECL(int) RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(RTCRSTORE hStore, PCRTCRX509NAME pSubject,
214 PRTCRSTORECERTSEARCH pSearch)
215{
216 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
217 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
218 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE);
219 AssertPtrReturn(pSearch, VERR_INVALID_POINTER);
220
221 int rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, pSearch);
222 if (RT_SUCCESS(rc))
223 {
224 pSearch->auOpaque[2] = RTCRSTORECERTSEARCH_BY_SUBECT_OR_ALT_SUBJECT_BY_RFC5280;
225 pSearch->auOpaque[3] = (uintptr_t)pSubject;
226 }
227 return rc;
228}
229
230
231RTDECL(PCRTCRCERTCTX) RTCrStoreCertSearchNext(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch)
232{
233 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
234 AssertPtrReturn(pThis, NULL);
235 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, NULL);
236 AssertPtrReturn(pSearch, NULL);
237
238 PCRTCRCERTCTX pRet;
239 switch (pSearch->auOpaque[2])
240 {
241 default:
242 pRet = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, pSearch);
243 break;
244
245 case RTCRSTORECERTSEARCH_BY_SUBECT_OR_ALT_SUBJECT_BY_RFC5280:
246 {
247 PCRTCRX509NAME pSubject = (PCRTCRX509NAME)pSearch->auOpaque[3];
248 AssertPtrReturn(pSubject, NULL);
249
250 for (;;)
251 {
252 pRet = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, pSearch);
253 if (!pRet)
254 break;
255 if (pRet->pCert)
256 {
257 if (RTCrX509Certificate_MatchSubjectOrAltSubjectByRfc5280(pRet->pCert, pSubject))
258 break;
259 }
260 else if (pRet->pTaInfo)
261 {
262 if ( RTCrTafCertPathControls_IsPresent(&pRet->pTaInfo->CertPath)
263 && RTCrX509Name_MatchByRfc5280(&pRet->pTaInfo->CertPath.TaName, pSubject))
264 break;
265 }
266 RTCrCertCtxRelease(pRet);
267 }
268 break;
269 }
270 }
271 return pRet;
272}
273
274
275RTDECL(int) RTCrStoreCertSearchDestroy(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch)
276{
277 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
278 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
279 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE);
280 if (pSearch)
281 {
282 AssertPtrReturn(pSearch, VERR_INVALID_POINTER);
283 pThis->pProvider->pfnCertSearchDestroy(pThis->pvProvider, pSearch);
284 }
285 return VINF_SUCCESS;
286}
287
288
289
290RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore)
291{
292 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
293 AssertPtrReturn(pThis, UINT32_MAX);
294 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, UINT32_MAX);
295
296 RTCRSTORECERTSEARCH Search;
297 int rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search);
298 AssertRCReturn(rc, UINT32_MAX);
299
300
301 uint32_t cCerts = 0;
302 PCRTCRCERTCTX pCur;
303 while ((pCur = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search)) != NULL)
304 {
305 RTCrCertCtxRelease(pCur);
306 cCerts++;
307 }
308
309 return cCerts;
310}
311
312
313#ifdef IPRT_WITH_OPENSSL
314/*
315 * OpenSSL helper.
316 * OpenSSL helper.
317 * OpenSSL helper.
318 */
319
320RTDECL(int) RTCrStoreConvertToOpenSslCertStore(RTCRSTORE hStore, uint32_t fFlags, void **ppvOpenSslStore, PRTERRINFO pErrInfo)
321{
322 RT_NOREF(pErrInfo);
323 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
324 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
325 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE);
326 RT_NOREF_PV(fFlags);
327
328 /*
329 * Use the pfnCertFindAll method to add all certificates to the store we're returning.
330 */
331 int rc;
332 X509_STORE *pOsslStore = X509_STORE_new();
333 if (pOsslStore)
334 {
335 RTCRSTORECERTSEARCH Search;
336 rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search);
337 if (RT_SUCCESS(rc))
338 {
339 do
340 {
341 PCRTCRCERTCTX pCertCtx = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search);
342 if (!pCertCtx)
343 break;
344
345 if ( (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
346 && pCertCtx->cbEncoded > 0)
347 {
348 X509 *pOsslCert = NULL;
349 const unsigned char *pabEncoded = (const unsigned char *)pCertCtx->pabEncoded;
350 if (d2i_X509(&pOsslCert, &pabEncoded, pCertCtx->cbEncoded) == pOsslCert)
351 {
352 if (!X509_STORE_add_cert(pOsslStore, pOsslCert))
353 rc = VERR_NO_MEMORY;
354 X509_free(pOsslCert);
355 }
356 }
357
358 RTCrCertCtxRelease(pCertCtx);
359 } while (RT_SUCCESS(rc));
360
361 pThis->pProvider->pfnCertSearchDestroy(pThis->pvProvider, &Search);
362 if (RT_SUCCESS(rc))
363 {
364 *ppvOpenSslStore = pOsslStore;
365 return VINF_SUCCESS;
366 }
367 }
368 X509_STORE_free(pOsslStore);
369 }
370 else
371 rc = VERR_NO_MEMORY;
372 return rc;
373}
374
375
376RTDECL(int) RTCrStoreConvertToOpenSslCertStack(RTCRSTORE hStore, uint32_t fFlags, void **ppvOpenSslStack, PRTERRINFO pErrInfo)
377{
378 RT_NOREF(pErrInfo);
379 PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
380 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
381 AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE);
382 RT_NOREF_PV(fFlags);
383
384 /*
385 * Use the pfnCertFindAll method to add all certificates to the store we're returning.
386 */
387 int rc;
388 STACK_OF(X509) *pOsslStack = sk_X509_new_null();
389 if (pOsslStack)
390 {
391 RTCRSTORECERTSEARCH Search;
392 rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search);
393 if (RT_SUCCESS(rc))
394 {
395 do
396 {
397 PCRTCRCERTCTX pCertCtx = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search);
398 if (!pCertCtx)
399 break;
400
401 if ( (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
402 && pCertCtx->cbEncoded > 0)
403 {
404 X509 *pOsslCert = NULL;
405 const unsigned char *pabEncoded = (const unsigned char *)pCertCtx->pabEncoded;
406 if (d2i_X509(&pOsslCert, &pabEncoded, pCertCtx->cbEncoded) == pOsslCert)
407 {
408 if (!sk_X509_push(pOsslStack, pOsslCert))
409 {
410 rc = VERR_NO_MEMORY;
411 X509_free(pOsslCert);
412 }
413 }
414 }
415
416 RTCrCertCtxRelease(pCertCtx);
417 } while (RT_SUCCESS(rc));
418
419 pThis->pProvider->pfnCertSearchDestroy(pThis->pvProvider, &Search);
420 if (RT_SUCCESS(rc))
421 {
422 *ppvOpenSslStack = pOsslStack;
423 return VINF_SUCCESS;
424 }
425 }
426 sk_X509_pop_free(pOsslStack, X509_free);
427 }
428 else
429 rc = VERR_NO_MEMORY;
430 return rc;
431}
432
433#endif /* IPRT_WITH_OPENSSL */
434
435
436/*
437 * Certificate context.
438 * Certificate context.
439 * Certificate context.
440 */
441
442
443RTDECL(uint32_t) RTCrCertCtxRetain(PCRTCRCERTCTX pCertCtx)
444{
445 AssertPtrReturn(pCertCtx, UINT32_MAX);
446 PRTCRCERTCTXINT pThis = RT_FROM_MEMBER(pCertCtx, RTCRCERTCTXINT, Public);
447 AssertReturn(pThis->u32Magic == RTCRCERTCTXINT_MAGIC, UINT32_MAX);
448 uint32_t cRet = ASMAtomicIncU32(&pThis->cRefs);
449 Assert(cRet < 64);
450 return cRet;
451}
452
453
454RTDECL(uint32_t) RTCrCertCtxRelease(PCRTCRCERTCTX pCertCtx)
455{
456 if (!pCertCtx)
457 return 0;
458
459 AssertPtrReturn(pCertCtx, UINT32_MAX);
460 PRTCRCERTCTXINT pThis = RT_FROM_MEMBER(pCertCtx, RTCRCERTCTXINT, Public);
461 AssertReturn(pThis->u32Magic == RTCRCERTCTXINT_MAGIC, UINT32_MAX);
462 uint32_t cRet = ASMAtomicDecU32(&pThis->cRefs);
463 if (!cRet)
464 {
465 ASMAtomicWriteU32(&pThis->u32Magic, RTCRCERTCTXINT_MAGIC_DEAD);
466 pThis->pfnDtor(pThis);
467 }
468 return cRet;
469}
470
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