VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/pkix-verify.cpp@ 73603

Last change on this file since 73603 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: pkix-verify.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - Public Key Infrastructure API, Verification.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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/pkix.h>
33
34#include <iprt/err.h>
35#include <iprt/string.h>
36#include <iprt/crypto/digest.h>
37
38#ifdef IPRT_WITH_OPENSSL
39# include "internal/iprt-openssl.h"
40# include "openssl/evp.h"
41# ifndef OPENSSL_VERSION_NUMBER
42# error "Missing OPENSSL_VERSION_NUMBER!"
43# endif
44#endif
45
46
47RTDECL(int) RTCrPkixPubKeyVerifySignature(PCRTASN1OBJID pAlgorithm, PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey,
48 PCRTASN1BITSTRING pSignatureValue, const void *pvData, size_t cbData,
49 PRTERRINFO pErrInfo)
50{
51 /*
52 * Valid input.
53 */
54 AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER);
55 AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER);
56
57 if (pParameters)
58 {
59 AssertPtrReturn(pParameters, VERR_INVALID_POINTER);
60 if (pParameters->enmType == RTASN1TYPE_NULL)
61 pParameters = NULL;
62 }
63
64 AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER);
65 AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER);
66
67 AssertPtrReturn(pSignatureValue, VERR_INVALID_POINTER);
68 AssertReturn(RTAsn1BitString_IsPresent(pSignatureValue), VERR_INVALID_POINTER);
69
70 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
71 AssertReturn(cbData > 0, VERR_INVALID_PARAMETER);
72
73 /*
74 * Parameters are not currently supported (openssl code path).
75 */
76 if (pParameters)
77 return RTErrInfoSet(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL,
78 "Cipher algorithm parameters are not yet supported.");
79
80 /*
81 * Validate using IPRT.
82 */
83 RTCRPKIXSIGNATURE hSignature;
84 int rcIprt = RTCrPkixSignatureCreateByObjId(&hSignature, pAlgorithm, false /*fSigning*/, pPublicKey, pParameters);
85 if (RT_FAILURE(rcIprt))
86 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN,
87 "Unknown public key algorithm [IPRT]: %s", pAlgorithm->szObjId);
88
89 RTCRDIGEST hDigest;
90 rcIprt = RTCrDigestCreateByObjId(&hDigest, pAlgorithm);
91 if (RT_SUCCESS(rcIprt))
92 {
93 /* Calculate the digest. */
94 rcIprt = RTCrDigestUpdate(hDigest, pvData, cbData);
95 if (RT_SUCCESS(rcIprt))
96 {
97 rcIprt = RTCrPkixSignatureVerifyBitString(hSignature, hDigest, pSignatureValue);
98 if (RT_FAILURE(rcIprt))
99 RTErrInfoSet(pErrInfo, rcIprt, "RTCrPkixSignatureVerifyBitString failed");
100 }
101 else
102 RTErrInfoSet(pErrInfo, rcIprt, "RTCrDigestUpdate failed");
103 RTCrDigestRelease(hDigest);
104 }
105 else
106 RTErrInfoSetF(pErrInfo, rcIprt, "Unknown digest algorithm [IPRT]: %s", pAlgorithm->szObjId);
107 RTCrPkixSignatureRelease(hSignature);
108
109#ifdef IPRT_WITH_OPENSSL
110 /*
111 * Validate using OpenSSL EVP.
112 */
113 rtCrOpenSslInit();
114
115 /* Translate the algorithm ID into a EVP message digest type pointer. */
116 int iAlgoNid = OBJ_txt2nid(pAlgorithm->szObjId);
117 if (iAlgoNid == NID_undef)
118 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN,
119 "Unknown public key algorithm [OpenSSL]: %s", pAlgorithm->szObjId);
120 const char *pszAlgoSn = OBJ_nid2sn(iAlgoNid);
121
122# if OPENSSL_VERSION_NUMBER >= 0x10001000 && !defined(LIBRESSL_VERSION_NUMBER)
123 int idAlgoPkey = 0;
124 int idAlgoMd = 0;
125 if (!OBJ_find_sigid_algs(iAlgoNid, &idAlgoMd, &idAlgoPkey))
126 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
127 "OBJ_find_sigid_algs failed on %u (%s, %s)", iAlgoNid, pszAlgoSn, pAlgorithm->szObjId);
128 const EVP_MD *pEvpMdType = EVP_get_digestbynid(idAlgoMd);
129 if (!pEvpMdType)
130 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
131 "EVP_get_digestbynid failed on %d (%s, %s)", idAlgoMd, pszAlgoSn, pAlgorithm->szObjId);
132# else
133 const EVP_MD *pEvpMdType = EVP_get_digestbyname(pszAlgoSn);
134 if (!pEvpMdType)
135 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
136 "EVP_get_digestbyname failed on %s (%s)", pszAlgoSn, pAlgorithm->szObjId);
137# endif
138
139 EVP_MD_CTX *pEvpMdCtx = EVP_MD_CTX_create();
140 if (!pEvpMdCtx)
141 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "EVP_MD_CTX_create failed");
142 int rcOssl;
143 if (EVP_VerifyInit_ex(pEvpMdCtx, pEvpMdType, NULL /*engine*/))
144 {
145 /* Create an EVP public key. */
146 EVP_PKEY *pEvpPublicKey = EVP_PKEY_new();
147 if (pEvpPublicKey)
148 {
149# if OPENSSL_VERSION_NUMBER >= 0x10001000 && !defined(LIBRESSL_VERSION_NUMBER)
150 if (EVP_PKEY_set_type(pEvpPublicKey, idAlgoPkey))
151 {
152 int idKeyType = EVP_PKEY_base_id(pEvpPublicKey);
153# else
154 int idKeyType = pEvpPublicKey->type = EVP_PKEY_type(pEvpMdType->required_pkey_type[0]);
155# endif
156 if (idKeyType != NID_undef)
157 {
158 const unsigned char *puchPublicKey = RTASN1BITSTRING_GET_BIT0_PTR(pPublicKey);
159 if (d2i_PublicKey(idKeyType, &pEvpPublicKey, &puchPublicKey, RTASN1BITSTRING_GET_BYTE_SIZE(pPublicKey)))
160 {
161 /* Digest the data. */
162 EVP_VerifyUpdate(pEvpMdCtx, pvData, cbData);
163
164 /* Verify the signature. */
165 if (EVP_VerifyFinal(pEvpMdCtx,
166 RTASN1BITSTRING_GET_BIT0_PTR(pSignatureValue),
167 RTASN1BITSTRING_GET_BYTE_SIZE(pSignatureValue),
168 pEvpPublicKey) > 0)
169 rcOssl = VINF_SUCCESS;
170 else
171 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED, "EVP_VerifyFinal failed");
172 }
173 else
174 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED, "d2i_PublicKey failed");
175 }
176 else
177# if OPENSSL_VERSION_NUMBER < 0x10001000 || defined(LIBRESSL_VERSION_NUMBER)
178 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_type() failed");
179# else
180 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_base_id() failed");
181 }
182 else
183 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
184 "EVP_PKEY_set_type(%u) failed (sig algo %s)", idAlgoPkey, pszAlgoSn);
185# endif
186 /* Cleanup and return.*/
187 EVP_PKEY_free(pEvpPublicKey);
188 }
189 else
190 rcOssl = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "EVP_PKEY_new(%d) failed", iAlgoNid);
191 }
192 else
193 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED,
194 "EVP_VerifyInit_ex failed (algorithm type is %s / %s)", pszAlgoSn, pAlgorithm->szObjId);
195 EVP_MD_CTX_destroy(pEvpMdCtx);
196
197 /*
198 * Check the result.
199 */
200 if (RT_SUCCESS(rcIprt) && RT_SUCCESS(rcOssl))
201 return VINF_SUCCESS;
202 if (RT_FAILURE_NP(rcIprt) && RT_FAILURE_NP(rcOssl))
203 return rcIprt;
204 AssertMsgFailed(("rcIprt=%Rrc rcOssl=%Rrc\n", rcIprt, rcOssl));
205 if (RT_FAILURE_NP(rcOssl))
206 return rcOssl;
207#endif /* IPRT_WITH_OPENSSL */
208
209 return rcIprt;
210}
211
212
213RTDECL(int) RTCrPkixPubKeyVerifySignedDigest(PCRTASN1OBJID pAlgorithm, PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey,
214 void const *pvSignedDigest, size_t cbSignedDigest, RTCRDIGEST hDigest,
215 PRTERRINFO pErrInfo)
216{
217 /*
218 * Valid input.
219 */
220 AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER);
221 AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER);
222
223 if (pParameters)
224 {
225 AssertPtrReturn(pParameters, VERR_INVALID_POINTER);
226 if (pParameters->enmType == RTASN1TYPE_NULL)
227 pParameters = NULL;
228 }
229
230 AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER);
231 AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER);
232
233 AssertPtrReturn(pvSignedDigest, VERR_INVALID_POINTER);
234 AssertReturn(cbSignedDigest, VERR_INVALID_PARAMETER);
235
236 AssertPtrReturn(hDigest, VERR_INVALID_HANDLE);
237
238 /*
239 * Parameters are not currently supported (openssl code path).
240 */
241 if (pParameters)
242 return RTErrInfoSet(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL,
243 "Cipher algorithm parameters are not yet supported.");
244
245 /*
246 * Validate using IPRT.
247 */
248 RTCRPKIXSIGNATURE hSignature;
249 int rcIprt = RTCrPkixSignatureCreateByObjId(&hSignature, pAlgorithm, false /*fSigning*/, pPublicKey, pParameters);
250 if (RT_FAILURE(rcIprt))
251 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN,
252 "Unknown public key algorithm [IPRT]: %s", pAlgorithm->szObjId);
253
254 rcIprt = RTCrPkixSignatureVerify(hSignature, hDigest, pvSignedDigest, cbSignedDigest);
255 if (RT_FAILURE(rcIprt))
256 RTErrInfoSet(pErrInfo, rcIprt, "RTCrPkixSignatureVerifyBitString failed");
257
258 RTCrPkixSignatureRelease(hSignature);
259
260#if defined(IPRT_WITH_OPENSSL) \
261 && (OPENSSL_VERSION_NUMBER > 0x10000000L) /* 0.9.8 doesn't seem to have EVP_PKEY_CTX_set_signature_md. */
262 /*
263 * Validate using OpenSSL EVP.
264 */
265 rtCrOpenSslInit();
266
267 const char *pszAlgObjId = pAlgorithm->szObjId;
268 if (!strcmp(pszAlgObjId, RTCRX509ALGORITHMIDENTIFIERID_RSA))
269 {
270 pszAlgObjId = RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid(pszAlgObjId,
271 RTCrDigestGetAlgorithmOid(hDigest));
272 AssertMsgStmt(pszAlgObjId, ("enc=%s hash=%s\n", pAlgorithm->szObjId, RTCrDigestGetAlgorithmOid(hDigest)),
273 pszAlgObjId = RTCrDigestGetAlgorithmOid(hDigest));
274 }
275
276 /* Translate the algorithm ID into a EVP message digest type pointer. */
277 int iAlgoNid = OBJ_txt2nid(pszAlgObjId);
278 if (iAlgoNid == NID_undef)
279 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN,
280 "Unknown public key algorithm [OpenSSL]: %s", pszAlgObjId);
281 const char *pszAlgoSn = OBJ_nid2sn(iAlgoNid);
282
283# if OPENSSL_VERSION_NUMBER >= 0x10001000 && !defined(LIBRESSL_VERSION_NUMBER)
284 int idAlgoPkey = 0;
285 int idAlgoMd = 0;
286 if (!OBJ_find_sigid_algs(iAlgoNid, &idAlgoMd, &idAlgoPkey))
287 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
288 "OBJ_find_sigid_algs failed on %u (%s, %s)", iAlgoNid, pszAlgoSn, pAlgorithm->szObjId);
289 const EVP_MD *pEvpMdType = EVP_get_digestbynid(idAlgoMd);
290 if (!pEvpMdType)
291 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
292 "EVP_get_digestbynid failed on %d (%s, %s)", idAlgoMd, pszAlgoSn, pAlgorithm->szObjId);
293# else
294 const EVP_MD *pEvpMdType = EVP_get_digestbyname(pszAlgoSn);
295 if (!pEvpMdType)
296 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
297 "EVP_get_digestbyname failed on %s (%s)", pszAlgoSn, pszAlgObjId);
298# endif
299
300 /* Create an EVP public key. */
301 int rcOssl;
302 EVP_PKEY *pEvpPublicKey = EVP_PKEY_new();
303 if (pEvpPublicKey)
304 {
305# if OPENSSL_VERSION_NUMBER >= 0x10001000 && !defined(LIBRESSL_VERSION_NUMBER)
306 if (EVP_PKEY_set_type(pEvpPublicKey, idAlgoPkey))
307 {
308 int idKeyType = EVP_PKEY_base_id(pEvpPublicKey);
309# else
310 int idKeyType = pEvpPublicKey->type = EVP_PKEY_type(pEvpMdType->required_pkey_type[0]);
311# endif
312 if (idKeyType != NID_undef)
313
314 {
315 const unsigned char *puchPublicKey = RTASN1BITSTRING_GET_BIT0_PTR(pPublicKey);
316 if (d2i_PublicKey(idKeyType, &pEvpPublicKey, &puchPublicKey, RTASN1BITSTRING_GET_BYTE_SIZE(pPublicKey)))
317 {
318 /* Create an EVP public key context we can use to validate the digest. */
319 EVP_PKEY_CTX *pEvpPKeyCtx = EVP_PKEY_CTX_new(pEvpPublicKey, NULL);
320 if (pEvpPKeyCtx)
321 {
322 rcOssl = EVP_PKEY_verify_init(pEvpPKeyCtx);
323 if (rcOssl > 0)
324 {
325 rcOssl = EVP_PKEY_CTX_set_signature_md(pEvpPKeyCtx, pEvpMdType);
326 if (rcOssl > 0)
327 {
328 /* Get the digest from hDigest and verify it. */
329 rcOssl = EVP_PKEY_verify(pEvpPKeyCtx,
330 (uint8_t const *)pvSignedDigest,
331 cbSignedDigest,
332 RTCrDigestGetHash(hDigest),
333 RTCrDigestGetHashSize(hDigest));
334 if (rcOssl > 0)
335 rcOssl = VINF_SUCCESS;
336 else
337 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED,
338 "EVP_PKEY_verify failed (%d)", rcOssl);
339 }
340 else
341 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
342 "EVP_PKEY_CTX_set_signature_md failed (%d)", rcOssl);
343 }
344 else
345 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
346 "EVP_PKEY_verify_init failed (%d)", rcOssl);
347 EVP_PKEY_CTX_free(pEvpPKeyCtx);
348 }
349 else
350 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_CTX_new failed");
351 }
352 else
353 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED, "d2i_PublicKey failed");
354 }
355 else
356# if OPENSSL_VERSION_NUMBER < 0x10001000 || defined(LIBRESSL_VERSION_NUMBER)
357 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_type() failed");
358# else
359 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_base_id() failed");
360 }
361 else
362 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
363 "EVP_PKEY_set_type(%u) failed (sig algo %s)", idAlgoPkey, pszAlgoSn);
364# endif
365
366 /* Cleanup and return.*/
367 EVP_PKEY_free(pEvpPublicKey);
368 }
369 else
370 rcOssl = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "EVP_PKEY_new(%d) failed", iAlgoNid);
371
372 /*
373 * Check the result.
374 */
375 if (RT_SUCCESS(rcIprt) && RT_SUCCESS(rcOssl))
376 return VINF_SUCCESS;
377 if (RT_FAILURE_NP(rcIprt) && RT_FAILURE_NP(rcOssl))
378 return rcIprt;
379 AssertMsgFailed(("rcIprt=%Rrc rcOssl=%Rrc\n", rcIprt, rcOssl));
380 if (RT_FAILURE_NP(rcOssl))
381 return rcOssl;
382#endif /* IPRT_WITH_OPENSSL */
383
384 return rcIprt;
385}
386
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