VirtualBox

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

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

IPRT: Added RTCrDigestGetAlgorithmOid, RTCrDigestTypeToAlgorithmOid, RTCrPkixPubKeyVerifySignedDigest, RTCrX509AlgorithmIdentifier_CombineEncryptionAndDigest, RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid, and RTCrX509AlgorithmIdentifier_CompareDigestOidAndEncryptedDigestOid.

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