VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/store-inmem.cpp@ 84204

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

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
1/* $Id: store-inmem.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - In Memory 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 "store-internal.h"
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45/**
46 * A certificate entry in the in-memory store.
47 */
48typedef struct RTCRSTOREINMEMCERT
49{
50 /** The core certificate context. */
51 RTCRCERTCTXINT Core;
52 /** Internal copy of the flag (paranoia). */
53 uint32_t fFlags;
54 /** Decoded data. */
55 union
56 {
57 /** ASN.1 core structure for generic access. */
58 RTASN1CORE Asn1Core;
59 /** The decoded X.509 certificate (RTCRCERTCTX_F_ENC_X509_DER). */
60 RTCRX509CERTIFICATE X509Cert;
61 /** The decoded trust anchor info (RTCRCERTCTX_F_ENC_TAF_DER). */
62 RTCRTAFTRUSTANCHORINFO TaInfo;
63 } u;
64 /** Pointer to the store if still in it (no reference). */
65 struct RTCRSTOREINMEM *pStore;
66 /** The DER encoding of the certificate. */
67 uint8_t abEncoded[1];
68} RTCRSTOREINMEMCERT;
69AssertCompileMembersAtSameOffset(RTCRSTOREINMEMCERT, u.X509Cert.SeqCore.Asn1Core, RTCRSTOREINMEMCERT, u.Asn1Core);
70AssertCompileMembersAtSameOffset(RTCRSTOREINMEMCERT, u.TaInfo.SeqCore.Asn1Core, RTCRSTOREINMEMCERT, u.Asn1Core);
71/** Pointer to an in-memory store certificate entry. */
72typedef RTCRSTOREINMEMCERT *PRTCRSTOREINMEMCERT;
73
74
75/**
76 * The per instance data of a in-memory crypto store.
77 *
78 * Currently we ASSUME we don't need serialization. Add that when needed!
79 */
80typedef struct RTCRSTOREINMEM
81{
82 /** The number of certificates. */
83 uint32_t cCerts;
84 /** The max number of certificates papCerts can store before growing it. */
85 uint32_t cCertsAlloc;
86 /** Array of certificates. */
87 PRTCRSTOREINMEMCERT *papCerts;
88} RTCRSTOREINMEM;
89/** Pointer to an in-memory crypto store. */
90typedef RTCRSTOREINMEM *PRTCRSTOREINMEM;
91
92
93
94
95static DECLCALLBACK(void) rtCrStoreInMemCertEntry_Dtor(PRTCRCERTCTXINT pCertCtx)
96{
97 PRTCRSTOREINMEMCERT pEntry = (PRTCRSTOREINMEMCERT)pCertCtx;
98 AssertRelease(!pEntry->pStore);
99
100 pEntry->Core.pfnDtor = NULL;
101 RTAsn1VtDelete(&pEntry->u.Asn1Core);
102 RTMemFree(pEntry);
103}
104
105
106/**
107 * Internal method for allocating and initalizing a certificate entry in the
108 * in-memory store.
109 *
110 * @returns IPRT status code.
111 * @param pThis The in-memory store instance.
112 * @param fEnc RTCRCERTCTX_F_ENC_X509_DER or RTCRCERTCTX_F_ENC_TAF_DER.
113 * @param pbSrc The DER encoded X.509 certificate to add.
114 * @param cbSrc The size of the encoded certificate.
115 * @param pErrInfo Where to return extended error info. Optional.
116 * @param ppEntry Where to return the pointer to the new entry.
117 */
118static int rtCrStoreInMemCreateCertEntry(PRTCRSTOREINMEM pThis, uint32_t fEnc, uint8_t const *pbSrc, uint32_t cbSrc,
119 PRTERRINFO pErrInfo, PRTCRSTOREINMEMCERT *ppEntry)
120{
121 int rc;
122 PRTCRSTOREINMEMCERT pEntry = (PRTCRSTOREINMEMCERT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCRSTOREINMEMCERT, abEncoded[cbSrc]));
123 if (pEntry)
124 {
125 memcpy(pEntry->abEncoded, pbSrc, cbSrc);
126 pEntry->Core.u32Magic = RTCRCERTCTXINT_MAGIC;
127 pEntry->Core.cRefs = 1;
128 pEntry->Core.pfnDtor = rtCrStoreInMemCertEntry_Dtor;
129 pEntry->Core.Public.fFlags = fEnc;
130 pEntry->Core.Public.cbEncoded = cbSrc;
131 pEntry->Core.Public.pabEncoded = &pEntry->abEncoded[0];
132 if (fEnc == RTCRCERTCTX_F_ENC_X509_DER)
133 {
134 pEntry->Core.Public.pCert = &pEntry->u.X509Cert;
135 pEntry->Core.Public.pTaInfo = NULL;
136 }
137 else
138 {
139 pEntry->Core.Public.pCert = NULL;
140 pEntry->Core.Public.pTaInfo = &pEntry->u.TaInfo;
141 }
142 pEntry->pStore = pThis;
143
144 RTASN1CURSORPRIMARY Cursor;
145 RTAsn1CursorInitPrimary(&Cursor, &pEntry->abEncoded[0], cbSrc, pErrInfo, &g_RTAsn1DefaultAllocator,
146 RTASN1CURSOR_FLAGS_DER, "InMem");
147 if (fEnc == RTCRCERTCTX_F_ENC_X509_DER)
148 rc = RTCrX509Certificate_DecodeAsn1(&Cursor.Cursor, 0, &pEntry->u.X509Cert, "Cert");
149 else
150 rc = RTCrTafTrustAnchorInfo_DecodeAsn1(&Cursor.Cursor, 0, &pEntry->u.TaInfo, "TaInfo");
151 if (RT_SUCCESS(rc))
152 {
153 if (fEnc == RTCRCERTCTX_F_ENC_X509_DER)
154 rc = RTCrX509Certificate_CheckSanity(&pEntry->u.X509Cert, 0, pErrInfo, "Cert");
155 else
156 rc = RTCrTafTrustAnchorInfo_CheckSanity(&pEntry->u.TaInfo, 0, pErrInfo, "TaInfo");
157 if (RT_SUCCESS(rc))
158 {
159 *ppEntry = pEntry;
160 return VINF_SUCCESS;
161 }
162
163 RTAsn1VtDelete(&pEntry->u.Asn1Core);
164 }
165 RTMemFree(pEntry);
166 }
167 else
168 rc = VERR_NO_MEMORY;
169 return rc;
170}
171
172
173/**
174 * Grows the certificate pointer array to at least @a cMin entries.
175 *
176 * @returns IPRT status code.
177 * @param pThis The in-memory store instance.
178 * @param cMin The new minimum store size.
179 */
180static int rtCrStoreInMemGrow(PRTCRSTOREINMEM pThis, uint32_t cMin)
181{
182 AssertReturn(cMin <= _1M, VERR_OUT_OF_RANGE);
183 AssertReturn(cMin > pThis->cCertsAlloc, VERR_INTERNAL_ERROR_3);
184
185 if (cMin < 64)
186 cMin = RT_ALIGN_32(cMin, 8);
187 else
188 cMin = RT_ALIGN_32(cMin, 32);
189
190 void *pv = RTMemRealloc(pThis->papCerts, cMin * sizeof(pThis->papCerts[0]));
191 if (pv)
192 {
193 pThis->papCerts = (PRTCRSTOREINMEMCERT *)pv;
194 for (uint32_t i = pThis->cCertsAlloc; i < cMin; i++)
195 pThis->papCerts[i] = NULL;
196 pThis->cCertsAlloc = cMin;
197 return VINF_SUCCESS;
198 }
199 return VERR_NO_MEMORY;
200}
201
202
203
204/** @interface_method_impl{RTCRSTOREPROVIDER,pfnDestroyStore} */
205static DECLCALLBACK(void) rtCrStoreInMem_DestroyStore(void *pvProvider)
206{
207 PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
208
209 while (pThis->cCerts > 0)
210 {
211 uint32_t i = --pThis->cCerts;
212 PRTCRSTOREINMEMCERT pEntry = pThis->papCerts[i];
213 pThis->papCerts[i] = NULL;
214 AssertPtr(pEntry);
215
216 pEntry->pStore = NULL;
217 RTCrCertCtxRelease(&pEntry->Core.Public);
218 }
219
220 RTMemFree(pThis->papCerts);
221 pThis->papCerts = NULL;
222 RTMemFree(pThis);
223}
224
225
226/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertCtxQueryPrivateKey} */
227static DECLCALLBACK(int) rtCrStoreInMem_CertCtxQueryPrivateKey(void *pvProvider, PRTCRCERTCTXINT pCertCtx,
228 uint8_t *pbKey, size_t cbKey, size_t *pcbKeyRet)
229{
230 RT_NOREF_PV(pvProvider); RT_NOREF_PV(pCertCtx); RT_NOREF_PV(pbKey); RT_NOREF_PV(cbKey); RT_NOREF_PV(pcbKeyRet);
231 //PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
232 return VERR_NOT_FOUND;
233}
234
235
236/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertFindAll} */
237static DECLCALLBACK(int) rtCrStoreInMem_CertFindAll(void *pvProvider, PRTCRSTORECERTSEARCH pSearch)
238{
239 pSearch->auOpaque[0] = ~(uintptr_t)pvProvider;
240 pSearch->auOpaque[1] = 0;
241 pSearch->auOpaque[2] = ~(uintptr_t)0; /* For the front-end API. */
242 pSearch->auOpaque[3] = ~(uintptr_t)0; /* For the front-end API. */
243 return VINF_SUCCESS;
244}
245
246
247/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertSearchNext} */
248static DECLCALLBACK(PCRTCRCERTCTX) rtCrStoreInMem_CertSearchNext(void *pvProvider, PRTCRSTORECERTSEARCH pSearch)
249{
250 PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
251 AssertReturn(pSearch->auOpaque[0] == ~(uintptr_t)pvProvider, NULL);
252
253 uintptr_t i = pSearch->auOpaque[1];
254 if (i < pThis->cCerts)
255 {
256 pSearch->auOpaque[1] = i + 1;
257 PRTCRCERTCTXINT pCertCtx = &pThis->papCerts[i]->Core;
258 ASMAtomicIncU32(&pCertCtx->cRefs);
259 return &pCertCtx->Public;
260 }
261 return NULL;
262}
263
264
265/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertSearchDestroy} */
266static DECLCALLBACK(void) rtCrStoreInMem_CertSearchDestroy(void *pvProvider, PRTCRSTORECERTSEARCH pSearch)
267{
268 NOREF(pvProvider);
269 AssertReturnVoid(pSearch->auOpaque[0] == ~(uintptr_t)pvProvider);
270 pSearch->auOpaque[0] = 0;
271 pSearch->auOpaque[1] = 0;
272 pSearch->auOpaque[2] = 0;
273 pSearch->auOpaque[3] = 0;
274}
275
276
277/** @interface_method_impl{RTCRSTOREPROVIDER,pfnCertSearchDestroy} */
278static DECLCALLBACK(int) rtCrStoreInMem_CertAddEncoded(void *pvProvider, uint32_t fFlags,
279 uint8_t const *pbEncoded, uint32_t cbEncoded, PRTERRINFO pErrInfo)
280{
281 PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
282 int rc;
283
284 AssertMsgReturn( (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
285 || (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_TAF_DER
286 , ("Only X.509 and TAF DER are supported: %#x\n", fFlags), VERR_INVALID_FLAGS);
287
288 /*
289 * Check for duplicates if specified.
290 */
291 if (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND)
292 {
293 uint32_t iCert = pThis->cCerts;
294 while (iCert-- > 0)
295 {
296 PRTCRSTOREINMEMCERT pCert = pThis->papCerts[iCert];
297 if ( pCert->Core.Public.cbEncoded == cbEncoded
298 && pCert->Core.Public.fFlags == (fFlags & RTCRCERTCTX_F_ENC_MASK)
299 && memcmp(pCert->Core.Public.pabEncoded, pbEncoded, cbEncoded) == 0)
300 return VWRN_ALREADY_EXISTS;
301 }
302 }
303
304 /*
305 * Add it.
306 */
307 if (pThis->cCerts + 1 <= pThis->cCertsAlloc)
308 { /* likely */ }
309 else
310 {
311 rc = rtCrStoreInMemGrow(pThis, pThis->cCerts + 1);
312 if (RT_FAILURE(rc))
313 return rc;
314 }
315
316 rc = rtCrStoreInMemCreateCertEntry(pThis, fFlags & RTCRCERTCTX_F_ENC_MASK, pbEncoded, cbEncoded,
317 pErrInfo, &pThis->papCerts[pThis->cCerts]);
318 if (RT_SUCCESS(rc))
319 {
320 pThis->cCerts++;
321 return VINF_SUCCESS;
322 }
323 return rc;
324}
325
326
327/**
328 * In-memory store provider.
329 */
330static RTCRSTOREPROVIDER const g_rtCrStoreInMemProvider =
331{
332 "in-memory",
333 rtCrStoreInMem_DestroyStore,
334 rtCrStoreInMem_CertCtxQueryPrivateKey,
335 rtCrStoreInMem_CertFindAll,
336 rtCrStoreInMem_CertSearchNext,
337 rtCrStoreInMem_CertSearchDestroy,
338 rtCrStoreInMem_CertAddEncoded,
339 NULL,
340 42
341};
342
343
344/**
345 * Common worker for RTCrStoreCreateInMem and future constructors...
346 *
347 * @returns IPRT status code.
348 * @param ppStore Where to return the store instance.
349 */
350static int rtCrStoreInMemCreateInternal(PRTCRSTOREINMEM *ppStore)
351{
352 PRTCRSTOREINMEM pStore = (PRTCRSTOREINMEM)RTMemAlloc(sizeof(*pStore));
353 if (pStore)
354 {
355 pStore->cCerts = 0;
356 pStore->cCertsAlloc = 0;
357 pStore->papCerts = NULL;
358 *ppStore = pStore;
359 return VINF_SUCCESS;
360 }
361 *ppStore = NULL; /* shut up gcc-maybe-pita warning. */
362 return VERR_NO_MEMORY;
363}
364
365
366RTDECL(int) RTCrStoreCreateInMem(PRTCRSTORE phStore, uint32_t cSizeHint)
367{
368 PRTCRSTOREINMEM pStore;
369 int rc = rtCrStoreInMemCreateInternal(&pStore);
370 if (RT_SUCCESS(rc))
371 {
372 if (cSizeHint)
373 rc = rtCrStoreInMemGrow(pStore, RT_MIN(cSizeHint, 512));
374 if (RT_SUCCESS(rc))
375 {
376 rc = rtCrStoreCreate(&g_rtCrStoreInMemProvider, pStore, phStore);
377 if (RT_SUCCESS(rc))
378 return VINF_SUCCESS;
379 }
380 RTMemFree(pStore);
381 }
382 return rc;
383}
384RT_EXPORT_SYMBOL(RTCrStoreCreateInMem);
385
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