VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp@ 57613

Last change on this file since 57613 was 57613, checked in by vboxsync, 9 years ago

IPRT,UINetworkReply.cpp: Added RTPathGlob, a set of RTCrStoreCertAddWantedDir/File/Store, a RTCrStoreCertAddWantedFromFishingExpedition, RTCrStoreCertCheckWanted, RTCrStoreCertCount, RTFsIsCaseSensitive and RTFileOpenTemp. Reworked some RTHttp bits and UINetworkReply stuff - this needs testing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.2 KB
Line 
1/* $Id: store-cert-add-basic.cpp 57613 2015-09-04 02:19:44Z vboxsync $ */
2/** @file
3 * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromDir.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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/assert.h>
35#include <iprt/crypto/pem.h>
36#include <iprt/dir.h>
37#include <iprt/err.h>
38#include <iprt/file.h>
39#include <iprt/mem.h>
40#include <iprt/path.h>
41#include <iprt/sha.h>
42#include <iprt/string.h>
43
44#include "x509-internal.h"
45
46
47/*********************************************************************************************************************************
48* Global Variables *
49*********************************************************************************************************************************/
50/** BEGIN CERTIFICATE / END CERTIFICATE. */
51static RTCRPEMMARKERWORD const g_aWords_Certificate[] =
52{
53 { RT_STR_TUPLE("CERTIFICATE") }
54};
55
56/** BEGIN TRUSTED CERTIFICATE / END TRUSTED CERTIFICATE. */
57static RTCRPEMMARKERWORD const g_aWords_TrustedCertificate[] =
58{
59 { RT_STR_TUPLE("TRUSTED") },
60 { RT_STR_TUPLE("CERTIFICATE") }
61};
62
63/** BEGIN X509 CERTIFICATE / END X509 CERTIFICATE. (old) */
64static RTCRPEMMARKERWORD const g_aWords_X509Certificate[] =
65{
66 { RT_STR_TUPLE("X509") },
67 { RT_STR_TUPLE("CERTIFICATE") }
68};
69
70/**
71 * X509 Certificate markers.
72 *
73 * @remark See crypto/pem/pem.h in OpenSSL for a matching list.
74 */
75RTCRPEMMARKER const g_aX509CertificateMarkers[3] =
76{
77 { g_aWords_Certificate, RT_ELEMENTS(g_aWords_Certificate) },
78 { g_aWords_TrustedCertificate, RT_ELEMENTS(g_aWords_TrustedCertificate) },
79 { g_aWords_X509Certificate, RT_ELEMENTS(g_aWords_X509Certificate) }
80};
81
82
83
84/**
85 * Checks if we've found all the certificates already.
86 *
87 * @returns true if all found, false if not.
88 * @param afFound Indicator array.
89 * @param cWanted Number of wanted certificates.
90 */
91DECLINLINE(bool) rtCrStoreAllDone(bool const *afFound, size_t cWanted)
92{
93 while (cWanted-- > 0)
94 if (!afFound[cWanted])
95 return false;
96 return true;
97}
98
99
100/**
101 * Checks if the given certificate specs matches the given wanted poster.
102 *
103 * @returns true if match, false if not.
104 * @param pWanted The certificate wanted poster.
105 * @param cbEncoded The candidate certificate encoded size.
106 * @param paSha1 The candidate certificate SHA-1 fingerprint.
107 * @param paSha512 The candidate certificate SHA-512 fingerprint.
108 * @param pCert The decoded candidate certificate, optional. If not
109 * given the result will be uncertain.
110 */
111DECLINLINE(bool) rtCrStoreIsCertEqualToWanted(PCRTCRCERTWANTED pWanted,
112 size_t cbEncoded,
113 uint8_t const pabSha1[RTSHA1_HASH_SIZE],
114 uint8_t const pabSha512[RTSHA512_HASH_SIZE],
115 PCRTCRX509CERTIFICATE pCert)
116{
117 if ( pWanted->cbEncoded != cbEncoded
118 && pWanted->cbEncoded != 0)
119 return false;
120
121 if ( pWanted->fSha1Fingerprint
122 && memcmp(pWanted->abSha1, pabSha1, RTSHA1_HASH_SIZE) != 0)
123 return false;
124
125 if ( pWanted->fSha512Fingerprint
126 && memcmp(pWanted->abSha512, pabSha512, RTSHA512_HASH_SIZE) != 0)
127 return false;
128
129 if ( pWanted->pszSubject
130 && pCert
131 && !RTCrX509Name_MatchWithString(&pCert->TbsCertificate.Subject, pWanted->pszSubject))
132 return false;
133
134 return true;
135}
136
137
138/**
139 * Checks if a certificate is wanted.
140 *
141 * @returns true if match, false if not.
142 * @param paWanted The certificate wanted posters.
143 * @param cWanted The number of wanted posters.
144 * @param apfFound Found initicators running paralell to @a paWanted.
145 * @param cbEncoded The candidate certificate encoded size.
146 * @param paSha1 The candidate certificate SHA-1 fingerprint.
147 * @param paSha512 The candidate certificate SHA-512 fingerprint.
148 * @param pCert The decoded candidate certificate, optional. If not
149 * given the result will be uncertain.
150 */
151DECLINLINE(bool) rtCrStoreIsCertWanted(PCRTCRCERTWANTED paWanted, size_t cWanted, bool const *pafFound, size_t cbEncoded,
152 uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
153 PCRTCRX509CERTIFICATE pCert)
154{
155 for (size_t iCert = 0; iCert < cWanted; iCert++)
156 if (!pafFound[iCert])
157 if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
158 return true;
159 return false;
160}
161
162
163/**
164 * Marks a certificate as found after it has been added to the store.
165 *
166 * May actually mark several certificates as found if there are duplicates or
167 * ambiguities in the wanted list.
168 *
169 * @returns true if all have been found, false if more to search for.
170 *
171 * @param apfFound Found initicators running paralell to @a paWanted.
172 * This is what this function updates.
173 * @param paWanted The certificate wanted posters.
174 * @param cWanted The number of wanted posters.
175 * @param cbEncoded The candidate certificate encoded size.
176 * @param paSha1 The candidate certificate SHA-1 fingerprint.
177 * @param paSha512 The candidate certificate SHA-512 fingerprint.
178 * @param pCert The decoded candidate certificate, optional. If not
179 * given the result will be uncertain.
180 */
181static bool rtCrStoreMarkCertFound(bool *pafFound, PCRTCRCERTWANTED paWanted, size_t cWanted, size_t cbEncoded,
182 uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
183 PCRTCRX509CERTIFICATE pCert)
184{
185 size_t cFound = 0;
186 for (size_t iCert = 0; iCert < cWanted; iCert++)
187 if (pafFound[iCert])
188 cFound++;
189 else if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
190 {
191 pafFound[iCert] = true;
192 cFound++;
193 }
194 return cFound == cWanted;
195}
196
197
198RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc)
199{
200 /*
201 * Validate input.
202 */
203 AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
204
205 /*
206 * Enumerate all the certificates in the source store, adding them to the destination.
207 */
208 RTCRSTORECERTSEARCH Search;
209 int rc = RTCrStoreCertFindAll(hStoreSrc, &Search);
210 if (RT_SUCCESS(rc))
211 {
212 PCRTCRCERTCTX pCertCtx;
213 while ((pCertCtx = RTCrStoreCertSearchNext(hStoreSrc, &Search)) != NULL)
214 {
215 int rc2 = RTCrStoreCertAddEncoded(hStore, pCertCtx->fFlags | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
216 pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL);
217 if (RT_FAILURE(rc2))
218 {
219 rc = rc2;
220 if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
221 break;
222 }
223 RTCrCertCtxRelease(pCertCtx);
224 }
225
226 int rc2 = RTCrStoreCertSearchDestroy(hStoreSrc, &Search); AssertRC(rc2);
227 }
228 return rc;
229}
230RT_EXPORT_SYMBOL(RTCrStoreCertAddFromStore);
231
232
233RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore,
234 PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
235{
236 /*
237 * Validate input a little.
238 */
239 AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
240 fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
241
242 AssertReturn(cWanted, VERR_NOT_FOUND);
243 for (uint32_t i = 0; i < cWanted; i++)
244 {
245 AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
246 AssertReturn( paWanted[i].pszSubject
247 || paWanted[i].fSha1Fingerprint
248 || paWanted[i].fSha512Fingerprint,
249 VERR_INVALID_PARAMETER);
250 }
251
252 /*
253 * Make sure we've got a result array.
254 */
255 bool *pafFoundFree = NULL;
256 if (!pafFound)
257 {
258 pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
259 AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
260 }
261
262 /*
263 * Enumerate the store entries.
264 */
265 RTCRSTORECERTSEARCH Search;
266 int rc = RTCrStoreCertFindAll(hSrcStore, &Search);
267 if (RT_SUCCESS(rc))
268 {
269 rc = VWRN_NOT_FOUND;
270 PCRTCRCERTCTX pCertCtx;
271 while ((pCertCtx = RTCrStoreCertSearchNext(hSrcStore, &Search)) != NULL)
272 {
273 if ( (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
274 && pCertCtx->cbEncoded > 0
275 && pCertCtx->pCert)
276 {
277 /*
278 * If the certificate is wanted, try add it to the store.
279 */
280 uint8_t abSha1[RTSHA1_HASH_SIZE];
281 RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
282 uint8_t abSha512[RTSHA512_HASH_SIZE];
283 RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
284 if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
285 {
286 int rc2 = RTCrStoreCertAddEncoded(hStore,
287 RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
288 pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL /*pErrInfo*/);
289 if (RT_SUCCESS(rc2))
290 {
291 /*
292 * Mark it as found, stop if we've found all.
293 */
294 if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
295 pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
296 {
297 if (RT_SUCCESS(rc))
298 rc = VINF_SUCCESS;
299 RTCrCertCtxRelease(pCertCtx);
300 break;
301 }
302 }
303 else
304 {
305 /*
306 * Some error adding the certificate. Since it cannot be anything with
307 * the encoding, it must be something with the store or resources, so
308 * always return the error status.
309 */
310 rc = rc2;
311 if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
312 {
313 RTCrCertCtxRelease(pCertCtx);
314 break;
315 }
316 }
317 }
318 }
319 RTCrCertCtxRelease(pCertCtx);
320 }
321 int rc2 = RTCrStoreCertSearchDestroy(hSrcStore, &Search);
322 AssertRC(rc2);
323 }
324
325 if (pafFoundFree)
326 RTMemTmpFree(pafFoundFree);
327 return rc;
328}
329RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
330
331
332RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
333{
334 /*
335 * Validate input a little.
336 */
337 AssertReturn(cWanted, VERR_NOT_FOUND);
338 for (uint32_t i = 0; i < cWanted; i++)
339 {
340 AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
341 AssertReturn( paWanted[i].pszSubject
342 || paWanted[i].fSha1Fingerprint
343 || paWanted[i].fSha512Fingerprint,
344 VERR_INVALID_PARAMETER);
345 }
346 AssertPtrReturn(pafFound, VERR_INVALID_POINTER);
347
348 /*
349 * Clear the found array.
350 */
351 for (uint32_t iCert = 0; iCert < cWanted; iCert++)
352 pafFound[iCert] = false;
353
354 /*
355 * Enumerate the store entries.
356 */
357 RTCRSTORECERTSEARCH Search;
358 int rc = RTCrStoreCertFindAll(hStore, &Search);
359 if (RT_SUCCESS(rc))
360 {
361 rc = VWRN_NOT_FOUND;
362 PCRTCRCERTCTX pCertCtx;
363 while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
364 {
365 if ( (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
366 && pCertCtx->cbEncoded > 0
367 && pCertCtx->pCert)
368 {
369 /*
370 * Hash it and check if it's wanted. Stop when we've found all.
371 */
372 uint8_t abSha1[RTSHA1_HASH_SIZE];
373 RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
374 uint8_t abSha512[RTSHA512_HASH_SIZE];
375 RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
376 if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
377 {
378 rc = VINF_SUCCESS;
379 RTCrCertCtxRelease(pCertCtx);
380 break;
381 }
382 }
383 RTCrCertCtxRelease(pCertCtx);
384 }
385 int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search);
386 AssertRC(rc2);
387 }
388
389 return rc;
390}
391RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
392
393
394RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
395{
396 AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
397
398 size_t cbContent;
399 void *pvContent;
400 int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
401 if (RT_SUCCESS(rc))
402 {
403 /*
404 * Is it a java key store file?
405 */
406 if ( cbContent > 32
407 && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
408 && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
409 rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
410 /*
411 * No assume PEM or DER encoded binary certificate.
412 */
413 else
414 {
415 PCRTCRPEMSECTION pSectionHead;
416 rc = RTCrPemParseContent(pvContent, cbContent,
417 (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
418 ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
419 g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
420 &pSectionHead, pErrInfo);
421 if (RT_SUCCESS(rc))
422 {
423 PCRTCRPEMSECTION pCurSec = pSectionHead;
424 while (pCurSec)
425 {
426 int rc2 = RTCrStoreCertAddEncoded(hStore,
427 RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
428 pCurSec->pbData, pCurSec->cbData,
429 !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
430 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
431 {
432 rc = rc2;
433 if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
434 break;
435 }
436 pCurSec = pCurSec->pNext;
437 }
438
439 RTCrPemFreeSections(pSectionHead);
440 }
441 }
442 RTFileReadAllFree(pvContent, cbContent);
443 }
444 else
445 rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
446 return rc;
447}
448RT_EXPORT_SYMBOL(RTCrStoreCertAddFromFile);
449
450
451RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename,
452 PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
453{
454 /*
455 * Validate input a little.
456 */
457 AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
458 fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
459
460 AssertReturn(cWanted, VERR_NOT_FOUND);
461 for (uint32_t i = 0; i < cWanted; i++)
462 {
463 AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
464 AssertReturn( paWanted[i].pszSubject
465 || paWanted[i].fSha1Fingerprint
466 || paWanted[i].fSha512Fingerprint,
467 VERR_INVALID_PARAMETER);
468 }
469
470 /*
471 * Make sure we've got a result array.
472 */
473 bool *pafFoundFree = NULL;
474 if (!pafFound)
475 {
476 pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
477 AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
478 }
479
480 size_t cbContent;
481 void *pvContent;
482 int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
483 if (RT_SUCCESS(rc))
484 {
485 /*
486 * Is it a java key store file? If so, load it into a tmp store
487 * which we can search. Don't want to duplicate the JKS reader code.
488 */
489 if ( cbContent > 32
490 && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
491 && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
492 {
493 RTCRSTORE hTmpStore;
494 rc = RTCrStoreCreateInMem(&hTmpStore, 64);
495 if (RT_SUCCESS(rc))
496 {
497 rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
498 if (RT_SUCCESS(rc))
499 rc = RTCrStoreCertAddWantedFromStore(hStore, fFlags, hTmpStore, paWanted, cWanted, pafFound);
500 RTCrStoreRelease(hTmpStore);
501 }
502 else
503 rc = RTErrInfoSet(pErrInfo, rc, "Error creating temporary crypto store");
504 }
505 /*
506 * No assume PEM or DER encoded binary certificate. Inspect them one by one.
507 */
508 else
509 {
510 PCRTCRPEMSECTION pSectionHead;
511 rc = RTCrPemParseContent(pvContent, cbContent,
512 (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
513 ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
514 g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
515 &pSectionHead, pErrInfo);
516 if (RT_SUCCESS(rc))
517 {
518 rc = VWRN_NOT_FOUND;
519 for (PCRTCRPEMSECTION pCurSec = pSectionHead; pCurSec; pCurSec = pCurSec->pNext)
520 {
521 if (!pCurSec->cbData)
522 continue;
523
524 /*
525 * See if this is a binary blob we might be interested in.
526 */
527 uint8_t abSha1[RTSHA1_HASH_SIZE];
528 RTSha1(pCurSec->pbData, pCurSec->cbData, abSha1);
529 uint8_t abSha512[RTSHA512_HASH_SIZE];
530 RTSha1(pCurSec->pbData, pCurSec->cbData, abSha512);
531 if (!rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, NULL))
532 continue;
533
534 /*
535 * Decode the certificate so we can match the subject string.
536 */
537 RTASN1CURSORPRIMARY Cursor;
538 RTAsn1CursorInitPrimary(&Cursor, pCurSec->pbData, (uint32_t)pCurSec->cbData,
539 !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL,
540 &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "InMem");
541 RTCRX509CERTIFICATE X509Cert;
542 int rc2 = RTCrX509Certificate_DecodeAsn1(&Cursor.Cursor, 0, &X509Cert, "Cert");
543 if (RT_SUCCESS(rc2))
544 {
545 rc2 = RTCrX509Certificate_CheckSanity(&X509Cert, 0, !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL, "Cert");
546 if (RT_SUCCESS(rc2))
547 {
548 if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, &X509Cert))
549 {
550 /*
551 * The certificate is wanted, now add it to the store.
552 */
553 rc2 = RTCrStoreCertAddEncoded(hStore,
554 RTCRCERTCTX_F_ENC_X509_DER
555 | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
556 pCurSec->pbData, pCurSec->cbData,
557 !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
558 if (RT_SUCCESS(rc2))
559 {
560 /*
561 * Mark it as found, stop if we've found all.
562 */
563 if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
564 pCurSec->cbData, abSha1, abSha512, &X509Cert))
565 {
566 RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
567 rc = VINF_SUCCESS;
568 break;
569 }
570 }
571 }
572 }
573 else
574 Assert(!pErrInfo || RTErrInfoIsSet(pErrInfo));
575 RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
576 }
577 else if (!RTErrInfoIsSet(pErrInfo))
578 RTErrInfoSetF(pErrInfo, rc2, "RTCrX509Certificate_DecodeAsn1 failed");
579
580 /*
581 * Stop on error, if requested. Otherwise, let pErrInfo keep it.
582 */
583 if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
584 {
585 rc = rc2;
586 break;
587 }
588 } /* For each PEM section. */
589
590 RTCrPemFreeSections(pSectionHead);
591 }
592 }
593 RTFileReadAllFree(pvContent, cbContent);
594 }
595 else
596 rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
597
598 if (pafFoundFree)
599 RTMemTmpFree(pafFoundFree);
600 return rc;
601}
602RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromFile);
603
604
605/**
606 * Checks if the directory entry matches the specified suffixes.
607 *
608 * @returns true on match, false on mismatch.
609 * @param pDirEntry The directory to check.
610 * @param paSuffixes The array of suffixes to match against.
611 * @param cSuffixes The number of suffixes in the array.
612 */
613DECLINLINE(bool) rtCrStoreIsSuffixMatch(PCRTDIRENTRY pDirEntry, PCRTSTRTUPLE paSuffixes, size_t cSuffixes)
614{
615 if (cSuffixes == 0)
616 return true;
617
618 size_t const cchName = pDirEntry->cbName;
619 size_t i = cSuffixes;
620 while (i-- > 0)
621 if ( cchName > paSuffixes[i].cch
622 && memcmp(&pDirEntry->szName[cchName - paSuffixes[i].cch], paSuffixes[i].psz, paSuffixes[i].cch) == 0)
623 return true;
624
625 return false;
626}
627
628
629RTDECL(int) RTCrStoreCertAddFromDir(RTCRSTORE hStore, uint32_t fFlags, const char *pszDir,
630 PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo)
631{
632 /*
633 * Validate input.
634 */
635 AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
636 size_t i = cSuffixes;
637 while (i-- > 0)
638 {
639 Assert(paSuffixes[i].cch > 0);
640 Assert(strlen(paSuffixes[i].psz) == paSuffixes[i].cch);
641 }
642
643 /*
644 * Prepare for constructing path to the files in the directory, so that we
645 * can open them.
646 */
647 char szPath[RTPATH_MAX];
648 int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
649 if (RT_SUCCESS(rc))
650 {
651 size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
652 if (cchPath > 0)
653 {
654 size_t const cbMaxFilename = sizeof(szPath) - cchPath;
655
656 /*
657 * Enumerate the directory.
658 */
659 PRTDIR hDir;
660 rc = RTDirOpen(&hDir, pszDir);
661 if (RT_SUCCESS(rc))
662 {
663 for (;;)
664 {
665 /* Read the next entry. */
666 union
667 {
668 RTDIRENTRY DirEntry;
669 uint8_t ab[RTPATH_MAX];
670 } u;
671 size_t cbBuf = sizeof(u);
672 int rc2 = RTDirRead(hDir, &u.DirEntry, &cbBuf);
673 if (RT_SUCCESS(rc2))
674 {
675 if ( ( u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
676 || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
677 || ( u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
678 && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
679 && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
680 {
681 if (u.DirEntry.cbName < cbMaxFilename)
682 {
683 memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName + 1);
684 rc2 = RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
685 if ( RT_SUCCESS(rc2)
686 && u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
687 {
688 /*
689 * Add it.
690 */
691 rc2 = RTCrStoreCertAddFromFile(hStore, fFlags, szPath, pErrInfo);
692 if (RT_FAILURE(rc2))
693 {
694 rc = rc2;
695 if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
696 break;
697 }
698 }
699 }
700 else
701 {
702 rc = RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
703 " Too long filename (%u bytes)", u.DirEntry.cbName);
704 if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
705 break;
706 }
707 }
708 }
709 else
710 {
711 if (rc2 != VERR_NO_MORE_FILES)
712 rc = RTErrInfoAddF(pErrInfo, rc2, " RTDirRead failed: %Rrc", rc2);
713 break;
714 }
715 }
716
717 RTDirClose(hDir);
718 }
719 else
720 rc = RTErrInfoAddF(pErrInfo, rc, " RTDirOpen('%s'): %Rrc", pszDir, rc);
721 }
722 else
723 rc = VERR_FILENAME_TOO_LONG;
724 }
725 return rc;
726}
727RT_EXPORT_SYMBOL(RTCrStoreCertAddFromDir);
728
729
730RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags,
731 const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes,
732 PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
733{
734 /*
735 * Validate input a little.
736 */
737 AssertReturn(*pszDir, VERR_PATH_ZERO_LENGTH);
738 AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
739 fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
740
741 AssertReturn(cWanted, VERR_NOT_FOUND);
742 for (uint32_t i = 0; i < cWanted; i++)
743 {
744 AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
745 AssertReturn( paWanted[i].pszSubject
746 || paWanted[i].fSha1Fingerprint
747 || paWanted[i].fSha512Fingerprint,
748 VERR_INVALID_PARAMETER);
749 }
750
751 /*
752 * Prepare for constructing path to the files in the directory, so that we
753 * can open them.
754 */
755 char szPath[RTPATH_MAX];
756 int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
757 if (RT_SUCCESS(rc))
758 {
759 size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
760 if (cchPath > 0)
761 {
762 size_t const cbMaxFilename = sizeof(szPath) - cchPath;
763
764 /*
765 * Enumerate the directory.
766 */
767 PRTDIR hDir;
768 rc = RTDirOpen(&hDir, pszDir);
769 if (RT_SUCCESS(rc))
770 {
771 rc = VWRN_NOT_FOUND;
772 for (;;)
773 {
774 /* Read the next entry. */
775 union
776 {
777 RTDIRENTRY DirEntry;
778 uint8_t abPadding[RT_OFFSETOF(RTDIRENTRY, szName) + RTPATH_MAX];
779 } u;
780 size_t cbEntry = sizeof(u);
781 int rc2 = RTDirRead(hDir, &u.DirEntry, &cbEntry);
782 if (RT_SUCCESS(rc2))
783 {
784 if ( ( u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
785 || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
786 || ( u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
787 && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
788 && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
789 {
790 if (u.DirEntry.cbName < cbMaxFilename)
791 {
792 memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName);
793 szPath[cchPath + u.DirEntry.cbName] = '\0';
794 if (u.DirEntry.enmType != RTDIRENTRYTYPE_FILE)
795 RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
796 if (u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
797 {
798 rc2 = RTCrStoreCertAddWantedFromFile(hStore, fFlags, szPath,
799 paWanted, cWanted, pafFound, pErrInfo);
800 if (rc2 == VINF_SUCCESS)
801 {
802 Assert(rtCrStoreAllDone(pafFound, cWanted));
803 if (RT_SUCCESS(rc))
804 rc = VINF_SUCCESS;
805 break;
806 }
807 if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
808 {
809 rc = rc2;
810 break;
811 }
812 }
813 }
814 else
815 {
816 /*
817 * pErrInfo keeps the status code unless it's fatal.
818 */
819 RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
820 " Too long filename (%u bytes)", u.DirEntry.cbName);
821 if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
822 {
823 rc = VERR_FILENAME_TOO_LONG;
824 break;
825 }
826 }
827 }
828 }
829 else
830 {
831 if (rc2 != VERR_NO_MORE_FILES)
832 {
833 RTErrInfoAddF(pErrInfo, rc2, "RTDirRead failed: %Rrc", rc2);
834 if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
835 rc = rc2;
836 }
837 break;
838 }
839 }
840 RTDirClose(hDir);
841 }
842 }
843 else
844 rc = VERR_FILENAME_TOO_LONG;
845 }
846 return rc;
847}
848RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromDir);
849
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