VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/checksum/x509.cpp@ 50954

Last change on this file since 50954 was 50954, checked in by vboxsync, 11 years ago

x509.cpp/h: Cleaned up rtX509ReadCertificateFromPEM, please study the changes and clean up the rest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: x509.cpp 50954 2014-04-02 16:19:56Z vboxsync $ */
2/** @file
3 * IPRT - X509 functions.
4 */
5
6/*
7 * Copyright (C) 2014 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/x509.h>
33
34#include <iprt/assert.h>
35#include <iprt/mem.h>
36#include <iprt/err.h>
37#include <iprt/sha.h>
38#include <iprt/manifest.h>
39#include <iprt/string.h>
40
41#include <openssl/bio.h>
42#include <openssl/err.h>
43#include <openssl/pem.h>
44#include <openssl/x509.h>
45#include <openssl/x509v3.h>
46
47
48/**
49 * Preparation before start to work with openssl
50 *
51 * @returns IPRT status code.
52 */
53RTDECL(int) RTX509PrepareOpenSSL(void)
54{
55 OpenSSL_add_all_digests();
56 ERR_load_BIO_strings();
57 ERR_load_crypto_strings();
58 return VINF_SUCCESS;
59}
60RT_EXPORT_SYMBOL(RTX509PrepareOpenSSL);
61
62
63/**
64 * Read X509 certificate from the given memory buffer into the internal
65 * structure.
66 *
67 * @returns IPRT status code.
68 *
69 * @param pvBuf String representation containing X509
70 * certificate in PEM format.
71 * @param cbBuf The amount of data @a pvBuf points to.
72 * @param ppOutCert Where to store the pointer to the structure where
73 * the info about X509 certificate will be stored.
74 */
75static int rtX509ReadCertificateFromPEM(void const *pvPem, unsigned int cbPem, X509 **ppOutCert)
76{
77 BIO *pBio = BIO_new(BIO_s_mem());
78 if (!pBio)
79 return VERR_NO_MEMORY;
80
81 int cb = BIO_write(pBio, pvPem, cbPem);
82 *ppOutCert = PEM_read_bio_X509(pBio, NULL, 0, NULL);
83 BIO_free(pBio);
84
85 return *ppOutCert ? VINF_SUCCESS : VERR_X509_READING_CERT_FROM_BIO;
86}
87
88
89/**
90 * Convert X509 certificate from string to binary representation
91 *
92 * @returns iprt status code.
93 *
94 * @param pvBuf string representation
95 * containing X509 certificate
96 * in PEM format
97 * @param pOutSignature memory buffer where the binary
98 * representation will be stored
99 * @param lengthOfSignature length of X509 certificate in
100 * binary representation
101 */
102static int RTX509ConvertCertificateToBinary(void *pvBuf, unsigned char** pOutSignature, unsigned int* lengthOfSignature)
103{
104 int rc = VINF_SUCCESS;
105
106 char* beginSignatureStr = RTStrStr((char*)pvBuf, "=");
107 beginSignatureStr+=2;
108 char* endSignatureStr = RTStrStr((char*)pvBuf, "-----BEGIN CERTIFICATE-----");
109 --endSignatureStr;
110 *lengthOfSignature = (endSignatureStr - beginSignatureStr)/2;//two hex digits in one byte
111 *pOutSignature = (unsigned char *)RTMemAlloc(*lengthOfSignature);
112
113 rc = RTStrConvertHexBytes(beginSignatureStr, *pOutSignature, *lengthOfSignature, 0);
114
115 if (RT_FAILURE(rc))
116 {
117 RTMemFree(*pOutSignature);
118 *pOutSignature = NULL;
119 }
120 return rc;
121}
122
123/**
124 * Convert digest from string to binary representation
125 *
126 * @returns iprt status code.
127 *
128 * @param digest string representation
129 * @param pOutDigest memory buffer where the binary
130 * representation will be stored
131 * @param digestType Type of digest
132 * @param lengthOfDigest length of digest in binary
133 * representation
134 */
135static int RTConvertDigestToBinary(const char* digest,
136 unsigned char** pOutDigest,
137 RTDIGESTTYPE digestType,
138 unsigned int* lengthOfDigest)
139{
140 int rc = VINF_SUCCESS;
141
142 if(digestType == RTDIGESTTYPE_SHA1)
143 {
144 *lengthOfDigest = RTSHA1_HASH_SIZE;
145 *pOutDigest = (unsigned char *)RTMemAlloc(RTSHA1_HASH_SIZE);
146 rc = RTStrConvertHexBytes(digest, *pOutDigest, RTSHA1_HASH_SIZE, 0);
147 }
148 else if(digestType == RTDIGESTTYPE_SHA256)
149 {
150 *lengthOfDigest = RTSHA256_HASH_SIZE;
151 *pOutDigest = (unsigned char *)RTMemAlloc(RTSHA256_HASH_SIZE);
152 rc = RTStrConvertHexBytes(digest, *pOutDigest, RTSHA256_HASH_SIZE, 0);
153 }
154 else
155 {
156 rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
157 }
158
159 if (RT_FAILURE(rc))
160 {
161 if(*pOutDigest != NULL)
162 RTMemFree(*pOutDigest);
163 *pOutDigest = NULL;
164 }
165
166 return rc;
167}
168
169RTDECL(int) RTRSAVerify(void *pvBuf, unsigned int cbSize, const char* pManifestDigestIn, RTDIGESTTYPE digestType)
170{
171 int rc = VINF_SUCCESS;
172 unsigned char* pSignatureRSA = NULL;
173 unsigned char* pManifestDigestOut = NULL;
174 X509 *certificate = NULL;
175 EVP_PKEY * evp_key = NULL;
176 RSA * rsa_key = NULL;
177
178 while(1)
179 {
180 unsigned int siglen = 0;
181 rc = RTX509ConvertCertificateToBinary(pvBuf, &pSignatureRSA, &siglen);
182 if (RT_FAILURE(rc))
183 {
184 /*pSignatureRSA isn't allocated in this case, thus there is no need to free it*/
185 break;
186 }
187
188 unsigned int diglen = 0;
189 rc = RTConvertDigestToBinary(pManifestDigestIn,&pManifestDigestOut, digestType, &diglen);
190 if (RT_FAILURE(rc))
191 {
192 /*pManifestDigestOut isn't allocated in this case, thus there is no need to free it*/
193 break;
194 }
195
196 rc = rtX509ReadCertificateFromPEM(pvBuf, cbSize, &certificate);
197 if (RT_FAILURE(rc))
198 {
199 /*memory for certificate isn't allocated in this case, thus there is no need to free it*/
200 break;
201 }
202
203 evp_key = X509_get_pubkey(certificate);
204 if (evp_key == NULL)
205 {
206 rc = VERR_X509_EXTRACT_PUBKEY_FROM_CERT;
207 break;
208 }
209
210 rsa_key = EVP_PKEY_get1_RSA(evp_key);
211 if (rsa_key == NULL)
212 {
213 rc = VERR_X509_EXTRACT_RSA_FROM_PUBLIC_KEY;
214 break;
215 }
216
217 rc = RSA_verify(NID_sha1,
218 pManifestDigestOut,
219 diglen,
220 pSignatureRSA,
221 siglen,
222 rsa_key);
223
224 if (rc != 1)
225 {
226 rc = VERR_X509_RSA_VERIFICATION_FUILURE;
227 }
228
229 break;
230 }//end while(1)
231
232 if(rsa_key)
233 RSA_free(rsa_key);
234 if(evp_key)
235 EVP_PKEY_free(evp_key);
236 if(certificate)
237 X509_free(certificate);
238 if (pManifestDigestOut)
239 RTMemFree(pManifestDigestOut);
240 if (pSignatureRSA)
241 RTMemFree(pSignatureRSA);
242
243 return rc;
244}
245RT_EXPORT_SYMBOL(RTRSAVerify);
246
247/**
248 * Get X509 certificate basic constraints
249 *
250 * @returns iprt status code.
251 *
252 * @param pvBuf string representation
253 * containing X509 certificate
254 * in PEM format
255 * @param cbSize The amount of data (in bytes)
256 * @param pBasicConstraintsOut memory buffer where the
257 * extracted basic constraints
258 * will be stored in string
259 * representation
260 */
261static int RTX509GetBasicConstraints(void *pvBuf, unsigned int cbSize, unsigned char** pBasicConstraintsOut)
262{
263 int rc = VINF_SUCCESS;
264 BUF_MEM *bptr = NULL;
265 X509 *certificate = NULL;
266 char *errDesc = NULL;
267 BIO *bio_memory = NULL;
268
269 for (;;)
270 {
271 rc = rtX509ReadCertificateFromPEM(pvBuf, cbSize, &certificate);
272 int loc = X509_get_ext_by_NID(certificate, NID_basic_constraints,-1);
273
274 if(loc == -1)
275 {
276 rc = VERR_X509_NO_BASIC_CONSTARAINTS;
277 break;
278 }
279
280 X509_EXTENSION *ext = X509_get_ext(certificate, loc);
281 if(!ext)
282 {
283 rc = VERR_X509_GETTING_EXTENSION_FROM_CERT;
284 break;
285 }
286
287 ASN1_OCTET_STRING *extdata = X509_EXTENSION_get_data(ext);
288 if(!extdata)
289 {
290 rc = VERR_X509_GETTING_DATA_FROM_EXTENSION;
291 break;
292 }
293
294 bio_memory = BIO_new(BIO_s_mem());
295 if(!X509V3_EXT_print(bio_memory, ext, 0, 0))
296 {
297 rc = VERR_X509_PRINT_EXTENSION_TO_BIO;
298 break;
299 }
300 BIO_ctrl(bio_memory,BIO_CTRL_FLUSH,0,NULL);
301 BIO_ctrl(bio_memory,BIO_C_GET_BUF_MEM_PTR,0,(void *)&bptr);
302
303 // now bptr contains the strings of the key_usage
304 unsigned char *buf = (unsigned char *)RTMemAlloc((bptr->length + 1)*sizeof(char));
305 memcpy(buf, bptr->data, bptr->length);
306 // take care that bptr->data is NOT NULL terminated, so add '\0'
307 buf[bptr->length] = '\0';
308
309 *pBasicConstraintsOut = buf;
310
311 break;
312 }
313
314 if(certificate)
315 X509_free(certificate);
316
317 BIO_free(bio_memory);
318
319 return rc;
320}
321
322RTDECL(int) RTX509CertificateVerify(void *pvBuf, unsigned int cbSize)
323{
324 int rc = VINF_SUCCESS;
325
326 X509 *certificate = NULL;
327 X509_NAME * subject = NULL;
328 X509_NAME * issuer = NULL;
329 EVP_PKEY * evp_key = NULL;
330 unsigned char* strBasicConstraints = NULL;
331
332 while(1)
333 {
334 rc = rtX509ReadCertificateFromPEM(pvBuf, cbSize, &certificate);
335 if (RT_FAILURE(rc))
336 {
337 break;
338 }
339
340 rc = RTX509GetBasicConstraints(pvBuf, cbSize, &strBasicConstraints);
341 if (RT_FAILURE(rc))
342 {
343 break;
344 }
345
346 issuer = X509_get_issuer_name(certificate);
347
348 if(strcmp("CA:TRUE", (const char*)strBasicConstraints) == 0)
349 {
350 subject = X509_get_subject_name(certificate);
351 int ki=0;
352
353 if(X509_name_cmp(issuer, subject) == 0)
354 {
355 evp_key = X509_get_pubkey(certificate);
356 ki=X509_verify(certificate,evp_key);
357 if(ki>0)
358 {
359 /* if it's needed will do something with the verified certificate */
360 }
361 else
362 rc = VERR_X509_CERTIFICATE_VERIFICATION_FAILURE;
363 }
364 else
365 {
366 rc = VINF_X509_NOT_SELFSIGNED_CERTIFICATE;
367 }
368 }
369 else
370 {
371 rc = VINF_X509_NOT_SELFSIGNED_CERTIFICATE;
372 }
373
374 break;
375 }
376
377 if(certificate)
378 X509_free(certificate);
379 if(evp_key)
380 EVP_PKEY_free(evp_key);
381
382 RTMemFree(strBasicConstraints);
383
384 return rc;
385}
386RT_EXPORT_SYMBOL(RTX509CertificateVerify);
387
388
389RTDECL(unsigned long) RTX509GetErrorDescription(char** pErrorDesc)
390{
391 char *errorDescription = (char *)RTMemAlloc(256);// buffer must be at least 120 bytes long.
392 // see http://www.openssl.org/docs/crypto/ERR_error_string.html
393 unsigned long err = ERR_get_error();
394 ERR_error_string(err, errorDescription);
395
396 *pErrorDesc = errorDescription;
397
398 return err;
399}
400RT_EXPORT_SYMBOL(RTX509GetError);
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