VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/CertificateImpl.cpp@ 60334

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

CertificateImpl,ApplianceImpl: Drop the unwanted presence attribute and replaced by returning NULL object in IAppliance::getCertificate. Move the certificate object to the data structure. Dropped the clearly unwanted init() method that (a) kept wanting to relate to IAppliance which I though I made clear several times it should not, (b) create an Certificate object in a unready state where most attributes would assert in debug builds and possibly crash. Renamed the CertificateVersion bits and redid the query method to no assume stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 KB
Line 
1/* $Id: CertificateImpl.cpp 60334 2016-04-05 13:55:31Z vboxsync $ */
2/** @file
3 * ICertificate COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2008-2016 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
18#include <iprt/path.h>
19#include <iprt/cpp/utils.h>
20#include <VBox/com/array.h>
21#include <iprt/crypto/x509.h>
22
23#include "ProgressImpl.h"
24#include "CertificateImpl.h"
25#include "AutoCaller.h"
26#include "Global.h"
27#include "Logging.h"
28
29using namespace std;
30
31struct CertificateData
32{
33 CertificateData()
34 : fTrusted(false)
35 , fValidX509(false)
36 {
37 RT_ZERO(X509);
38 }
39
40 ~CertificateData()
41 {
42 if (fValidX509)
43 {
44 RTCrX509Certificate_Delete(&X509);
45 RT_ZERO(X509);
46 fValidX509 = false;
47 }
48 }
49
50 /** Whether the certificate is trusted. */
51 bool fTrusted;
52 /** Valid data in mX509. */
53 bool fValidX509;
54 /** Clone of the X.509 certificate. */
55 RTCRX509CERTIFICATE X509;
56
57private:
58 CertificateData(const CertificateData &rTodo) { AssertFailed(); NOREF(rTodo); }
59 CertificateData &operator=(const CertificateData &rTodo) { AssertFailed(); NOREF(rTodo); return *this; }
60};
61
62struct Certificate::Data
63{
64 Backupable<CertificateData> m;
65};
66
67///////////////////////////////////////////////////////////////////////////////////
68//
69// Certificate constructor / destructor
70//
71// ////////////////////////////////////////////////////////////////////////////////
72
73DEFINE_EMPTY_CTOR_DTOR(Certificate)
74
75HRESULT Certificate::FinalConstruct()
76{
77 return BaseFinalConstruct();
78}
79
80void Certificate::FinalRelease()
81{
82 uninit();
83 BaseFinalRelease();
84}
85
86/**
87 * Initializes a certificate instance.
88 *
89 * @returns COM status code.
90 * @param a_pCert The certificate.
91 * @param a_fTrusted Whether the caller trusts the certificate or not.
92 */
93HRESULT Certificate::initCertificate(PCRTCRX509CERTIFICATE a_pCert, bool a_fTrusted)
94{
95 HRESULT rc = S_OK;
96 LogFlowThisFuncEnter();
97
98 AutoInitSpan autoInitSpan(this);
99 AssertReturn(autoInitSpan.isOk(), E_FAIL);
100
101 mData = new Data();
102 mData->m.allocate();
103
104 int vrc = RTCrX509Certificate_Clone(&mData->m->X509, a_pCert, &g_RTAsn1DefaultAllocator);
105 if (RT_SUCCESS(vrc))
106 {
107 mData->m->fValidX509 = true;
108 mData->m->fTrusted = a_fTrusted;
109 autoInitSpan.setSucceeded();
110 }
111 else
112 rc = Global::vboxStatusCodeToCOM(vrc);
113
114 LogFlowThisFunc(("returns rc=%Rhrc\n", rc));
115 return rc;
116}
117
118void Certificate::uninit()
119{
120 /* Enclose the state transition Ready->InUninit->NotReady */
121 AutoUninitSpan autoUninitSpan(this);
122 if (autoUninitSpan.uninitDone())
123 return;
124
125 mData->m.free();
126 delete mData;
127 mData = NULL;
128}
129
130/**
131 * Private method implementation.
132 * @param aVersionNumber
133 * @return
134 */
135HRESULT Certificate::getVersionNumber(CertificateVersion_T *aVersionNumber)
136{
137 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
138
139 Assert(mData->m->fValidX509);
140 switch (mData->m->X509.TbsCertificate.T0.Version.uValue.u)
141 {
142 case RTCRX509TBSCERTIFICATE_V1: *aVersionNumber = (CertificateVersion_T)CertificateVersion_V1; break;
143 case RTCRX509TBSCERTIFICATE_V2: *aVersionNumber = (CertificateVersion_T)CertificateVersion_V2; break;
144 case RTCRX509TBSCERTIFICATE_V3: *aVersionNumber = (CertificateVersion_T)CertificateVersion_V3; break;
145 default: AssertFailed(); *aVersionNumber = (CertificateVersion_T)CertificateVersion_Unknown; break;
146 }
147 return S_OK;
148}
149
150/**
151 * Private method implementation.
152 * @param aSerialNumber
153 * @return
154 */
155HRESULT Certificate::getSerialNumber(com::Utf8Str &aSerialNumber)
156{
157 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
158
159 Assert(mData->m->fValidX509);
160
161 char szTmp[_2K];
162 int vrc = RTAsn1Integer_ToString(&mData->m->X509.TbsCertificate.SerialNumber, szTmp, sizeof(szTmp), 0, NULL);
163 if (RT_SUCCESS(vrc))
164 aSerialNumber = szTmp;
165 else
166 return Global::vboxStatusCodeToCOM(vrc);
167
168 return S_OK;
169}
170
171/**
172 * Private method implementation.
173 * @param aSignatureAlgorithmOID
174 * @return
175 */
176HRESULT Certificate::getSignatureAlgorithmOID(com::Utf8Str &aSignatureAlgorithmOID)
177{
178 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
179
180 Assert(mData->m->fValidX509);
181 aSignatureAlgorithmOID = mData->m->X509.TbsCertificate.Signature.Algorithm.szObjId;
182
183 return S_OK;
184}
185
186/**
187 * Private method implementation.
188 * @param aSignatureAlgorithmID
189 * @return
190 */
191HRESULT Certificate::getSignatureAlgorithmName(com::Utf8Str &aSignatureAlgorithmName)
192{
193 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
194
195 Assert(mData->m->fValidX509);
196 return i_getAlgorithmName(&mData->m->X509.TbsCertificate.Signature, aSignatureAlgorithmName);
197}
198
199/**
200 * Private method implementation.
201 * @param aIssuerName
202 * @return
203 */
204HRESULT Certificate::getIssuerName(std::vector<com::Utf8Str> &aIssuerName)
205{
206 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
207
208 Assert(mData->m->fValidX509);
209 return i_getX509Name(&mData->m->X509.TbsCertificate.Issuer, aIssuerName);
210}
211
212/**
213 * Private method implementation.
214 * @param aSubjectName
215 * @return
216 */
217HRESULT Certificate::getSubjectName(std::vector<com::Utf8Str> &aSubjectName)
218{
219 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
220
221 Assert(mData->m->fValidX509);
222 return i_getX509Name(&mData->m->X509.TbsCertificate.Subject, aSubjectName);
223}
224
225/**
226 * Private method implementation.
227 * @param aValidityPeriodNotBefore
228 * @return
229 */
230HRESULT Certificate::getValidityPeriodNotBefore(com::Utf8Str &aValidityPeriodNotBefore)
231{
232 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
233
234 Assert(mData->m->fValidX509);
235 return i_getTime(&mData->m->X509.TbsCertificate.Validity.NotBefore, aValidityPeriodNotBefore);
236}
237
238/**
239 * Private method implementation.
240 * @param aValidityPeriodNotAfter
241 * @return
242 */
243HRESULT Certificate::getValidityPeriodNotAfter(com::Utf8Str &aValidityPeriodNotAfter)
244{
245 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
246
247 Assert(mData->m->fValidX509);
248 return i_getTime(&mData->m->X509.TbsCertificate.Validity.NotAfter, aValidityPeriodNotAfter);
249}
250
251HRESULT Certificate::getPublicKeyAlgorithmOID(com::Utf8Str &aPublicKeyAlgorithmOID)
252{
253 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
254
255 Assert(mData->m->fValidX509);
256 aPublicKeyAlgorithmOID = mData->m->X509.TbsCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm.szObjId;
257 return S_OK;
258}
259
260/**
261 * Private method implementation.
262 * @param aPublicKeyAlgorithm
263 * @return
264 */
265HRESULT Certificate::getPublicKeyAlgorithm(com::Utf8Str &aPublicKeyAlgorithm)
266{
267 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
268
269 Assert(mData->m->fValidX509);
270 return i_getAlgorithmName(&mData->m->X509.TbsCertificate.SubjectPublicKeyInfo.Algorithm, aPublicKeyAlgorithm);
271}
272
273/**
274 * Private method implementation.
275 * @param aSubjectPublicKey
276 * @return
277 */
278HRESULT Certificate::getSubjectPublicKey(std::vector<BYTE> &aSubjectPublicKey)
279{
280
281 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Getting encoded ASN.1 bytes may make changes to X509. */
282 return i_getEncodedBytes(&mData->m->X509.TbsCertificate.SubjectPublicKeyInfo.SubjectPublicKey.Asn1Core, aSubjectPublicKey);
283}
284
285/**
286 * Private method implementation.
287 * @param aIssuerUniqueIdentifier
288 * @return
289 */
290HRESULT Certificate::getIssuerUniqueIdentifier(com::Utf8Str &aIssuerUniqueIdentifier)
291{
292 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
293
294 return i_getUniqueIdentifier(&mData->m->X509.TbsCertificate.T1.IssuerUniqueId, aIssuerUniqueIdentifier);
295}
296
297/**
298 * Private method implementation.
299 * @param aSubjectUniqueIdentifier
300 * @return
301 */
302HRESULT Certificate::getSubjectUniqueIdentifier(com::Utf8Str &aSubjectUniqueIdentifier)
303{
304 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
305
306 return i_getUniqueIdentifier(&mData->m->X509.TbsCertificate.T2.SubjectUniqueId, aSubjectUniqueIdentifier);
307}
308
309/**
310 * Private method implementation.
311 * @param aCertificateAuthority
312 * @return
313 */
314HRESULT Certificate::getCertificateAuthority(BOOL *aCertificateAuthority)
315{
316 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
317
318 *aCertificateAuthority = mData->m->X509.TbsCertificate.T3.pBasicConstraints
319 && mData->m->X509.TbsCertificate.T3.pBasicConstraints->CA.fValue;
320
321 return S_OK;
322}
323
324/**
325 * Private method implementation.
326 * @param aKeyUsage
327 * @return
328 */
329HRESULT Certificate::getKeyUsage(ULONG *aKeyUsage)
330{
331 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
332
333 *aKeyUsage = mData->m->X509.TbsCertificate.T3.fKeyUsage;
334 return S_OK;
335}
336
337/**
338 * Private method implementation.
339 * @param aExtendedKeyUsage
340 * @return
341 */
342HRESULT Certificate::getExtendedKeyUsage(std::vector<com::Utf8Str> &aExtendedKeyUsage)
343{
344 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
345 NOREF(aExtendedKeyUsage);
346 return E_NOTIMPL;
347}
348
349/**
350 * Private method implementation.
351 * @param aRawCertData
352 * @return
353 */
354HRESULT Certificate::getRawCertData(std::vector<BYTE> &aRawCertData)
355{
356 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /* Getting encoded ASN.1 bytes may make changes to X509. */
357 return i_getEncodedBytes(&mData->m->X509.SeqCore.Asn1Core, aRawCertData);
358}
359
360/**
361 * Private method implementation.
362 * @param aSelfSigned
363 * @return
364 */
365HRESULT Certificate::getSelfSigned(BOOL *aSelfSigned)
366{
367 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
368
369 Assert(mData->m->fValidX509);
370 *aSelfSigned = RTCrX509Certificate_IsSelfSigned(&mData->m->X509);
371
372 return S_OK;
373}
374
375/**
376 * Private method implementation.
377 * @param aTrusted
378 * @return
379 */
380HRESULT Certificate::getTrusted(BOOL *aTrusted)
381{
382 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
383
384 *aTrusted = mData->m->fTrusted;
385
386 return S_OK;
387}
388
389/**
390 * Private method implementation.
391 * @param aWhat
392 * @param aResult
393 * @return
394 */
395HRESULT Certificate::queryInfo(LONG aWhat, com::Utf8Str &aResult)
396{
397 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
398 /* Insurance. */
399 NOREF(aResult);
400 return setError(E_FAIL, "Unknown item %u", aWhat);
401}
402
403HRESULT Certificate::i_getAlgorithmName(PCRTCRX509ALGORITHMIDENTIFIER a_pAlgId, com::Utf8Str &a_rReturn)
404{
405 const char *pszOid = a_pAlgId->Algorithm.szObjId;
406 const char *pszName;
407 if (!pszOid) pszName = "";
408 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_RSA)) pszName = "rsaEncryption";
409 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_MD2_WITH_RSA)) pszName = "md2WithRSAEncryption";
410 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_MD4_WITH_RSA)) pszName = "md4WithRSAEncryption";
411 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_MD5_WITH_RSA)) pszName = "md5WithRSAEncryption";
412 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_SHA1_WITH_RSA)) pszName = "sha1WithRSAEncryption";
413 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_SHA224_WITH_RSA)) pszName = "sha224WithRSAEncryption";
414 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_SHA256_WITH_RSA)) pszName = "sha256WithRSAEncryption";
415 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_SHA384_WITH_RSA)) pszName = "sha384WithRSAEncryption";
416 else if (strcmp(pszOid, RTCRX509ALGORITHMIDENTIFIERID_SHA512_WITH_RSA)) pszName = "sha512WithRSAEncryption";
417 else
418 pszName = pszOid;
419 a_rReturn = pszName;
420 return S_OK;
421}
422
423HRESULT Certificate::i_getX509Name(PCRTCRX509NAME a_pName, std::vector<com::Utf8Str> &a_rReturn)
424{
425 if (RTCrX509Name_IsPresent(a_pName))
426 {
427 for (uint32_t i = 0; i < a_pName->cItems; i++)
428 {
429 PCRTCRX509RELATIVEDISTINGUISHEDNAME pRdn = &a_pName->paItems[i];
430 for (uint32_t j = 0; j < pRdn->cItems; j++)
431 {
432 PCRTCRX509ATTRIBUTETYPEANDVALUE pComponent = &pRdn->paItems[j];
433
434 AssertReturn(pComponent->Value.enmType == RTASN1TYPE_STRING,
435 setErrorVrc(VERR_CR_X509_NAME_NOT_STRING, "VERR_CR_X509_NAME_NOT_STRING"));
436
437 /* Get the prefix for this name component. */
438 const char *pszPrefix = RTCrX509Name_GetShortRdn(&pComponent->Type);
439 AssertStmt(pszPrefix, pszPrefix = pComponent->Type.szObjId);
440
441 /* Get the string. */
442 const char *pszUtf8;
443 int vrc = RTAsn1String_QueryUtf8(&pComponent->Value.u.String, &pszUtf8, NULL /*pcch*/);
444 AssertRCReturn(vrc, setErrorVrc(vrc, "RTAsn1String_QueryUtf8(%u/%u,,) -> %Rrc", i, j, vrc));
445
446 a_rReturn.push_back(Utf8StrFmt("%s=%s", pszPrefix, pszUtf8));
447 }
448 }
449 }
450 return S_OK;
451}
452
453HRESULT Certificate::i_getTime(PCRTASN1TIME a_pTime, com::Utf8Str &a_rReturn)
454{
455 char szTmp[128];
456 if (RTTimeToString(&a_pTime->Time, szTmp, sizeof(szTmp)))
457 {
458 a_rReturn = szTmp;
459 return S_OK;
460 }
461 AssertFailed();
462 return E_FAIL;
463}
464
465HRESULT Certificate::i_getUniqueIdentifier(PCRTCRX509UNIQUEIDENTIFIER a_pUniqueId, com::Utf8Str &a_rReturn)
466{
467 /* The a_pUniqueId may not be present! */
468 if (RTCrX509UniqueIdentifier_IsPresent(a_pUniqueId))
469 {
470 void const *pvData = RTASN1BITSTRING_GET_BIT0_PTR(a_pUniqueId);
471 size_t const cbData = RTASN1BITSTRING_GET_BYTE_SIZE(a_pUniqueId);
472 size_t const cbFormatted = cbData * 3 - 1 + 1;
473 a_rReturn.reserve(cbFormatted); /* throws */
474 int vrc = RTStrPrintHexBytes(a_rReturn.mutableRaw(), cbFormatted, pvData, cbData, RTSTRPRINTHEXBYTES_F_SEP_COLON);
475 a_rReturn.jolt();
476 AssertRCReturn(vrc, Global::vboxStatusCodeToCOM(vrc));
477 }
478 else
479 Assert(a_rReturn.isEmpty());
480 return S_OK;
481}
482
483HRESULT Certificate::i_getEncodedBytes(PRTASN1CORE a_pAsn1Obj, std::vector<BYTE> &a_rReturn)
484{
485 HRESULT hrc = S_OK;
486 Assert(a_rReturn.size() == 0);
487 if (RTAsn1Core_IsPresent(a_pAsn1Obj))
488 {
489 uint32_t cbEncoded;
490 int vrc = RTAsn1EncodePrepare(a_pAsn1Obj, 0, &cbEncoded, NULL);
491 if (RT_SUCCESS(vrc))
492 {
493 a_rReturn.resize(cbEncoded);
494 Assert(a_rReturn.size() == cbEncoded);
495 if (cbEncoded)
496 {
497 vrc = RTAsn1EncodeToBuffer(a_pAsn1Obj, 0, &a_rReturn.front(), a_rReturn.size(), NULL);
498 if (RT_FAILURE(vrc))
499 hrc = setErrorVrc(vrc, "RTAsn1EncodeToBuffer failed with %Rrc", vrc);
500 }
501 }
502 else
503 hrc = setErrorVrc(vrc, "RTAsn1EncodePrepare failed with %Rrc", vrc);
504 }
505 return hrc;
506}
507
508
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette