VirtualBox

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

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

IPRT/pkix-verify.cpp: rhel5 (openssl < 1.0.0) build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 KB
Line 
1/* $Id: pkix-verify.cpp 59695 2016-02-15 22:36:49Z 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# 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 *pszAlogSn = OBJ_nid2sn(iAlgoNid);
121 const EVP_MD *pEvpMdType = EVP_get_digestbyname(pszAlogSn);
122 if (!pEvpMdType)
123 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
124 "EVP_get_digestbyname failed on %s (%s)", pszAlogSn, pAlgorithm->szObjId);
125
126 /* Initialize the EVP message digest context. */
127 EVP_MD_CTX EvpMdCtx;
128 EVP_MD_CTX_init(&EvpMdCtx);
129 if (!EVP_VerifyInit_ex(&EvpMdCtx, pEvpMdType, NULL /*engine*/))
130 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED,
131 "EVP_VerifyInit_ex failed (algorithm type is %s / %s)", pszAlogSn, pAlgorithm->szObjId);
132
133 /* Create an EVP public key. */
134 int rcOssl;
135 EVP_PKEY *pEvpPublicKey = EVP_PKEY_new();
136 if (pEvpPublicKey)
137 {
138 pEvpPublicKey->type = EVP_PKEY_type(pEvpMdType->required_pkey_type[0]);
139 if (pEvpPublicKey->type != NID_undef)
140 {
141 const unsigned char *puchPublicKey = RTASN1BITSTRING_GET_BIT0_PTR(pPublicKey);
142 if (d2i_PublicKey(pEvpPublicKey->type, &pEvpPublicKey, &puchPublicKey, RTASN1BITSTRING_GET_BYTE_SIZE(pPublicKey)))
143 {
144 /* Digest the data. */
145 EVP_VerifyUpdate(&EvpMdCtx, pvData, cbData);
146
147 /* Verify the signature. */
148 if (EVP_VerifyFinal(&EvpMdCtx,
149 RTASN1BITSTRING_GET_BIT0_PTR(pSignatureValue),
150 RTASN1BITSTRING_GET_BYTE_SIZE(pSignatureValue),
151 pEvpPublicKey) > 0)
152 rcOssl = VINF_SUCCESS;
153 else
154 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED, "EVP_VerifyFinal failed");
155 }
156 else
157 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED, "d2i_PublicKey failed");
158 }
159 else
160 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
161 "EVP_PKEY_type(%d) failed", pEvpMdType->required_pkey_type[0]);
162 /* Cleanup and return.*/
163 EVP_PKEY_free(pEvpPublicKey);
164 }
165 else
166 rcOssl = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "EVP_PKEY_new(%d) failed", pEvpMdType->required_pkey_type[0]);
167 EVP_MD_CTX_cleanup(&EvpMdCtx);
168
169 /*
170 * Check the result.
171 */
172 if (RT_SUCCESS(rcIprt) && RT_SUCCESS(rcOssl))
173 return VINF_SUCCESS;
174 if (RT_FAILURE_NP(rcIprt) && RT_FAILURE_NP(rcOssl))
175 return rcIprt;
176 AssertMsgFailed(("rcIprt=%Rrc rcOssl=%Rrc\n", rcIprt, rcOssl));
177 if (RT_FAILURE_NP(rcOssl))
178 return rcOssl;
179#endif /* IPRT_WITH_OPENSSL */
180
181 return rcIprt;
182}
183
184
185RTDECL(int) RTCrPkixPubKeyVerifySignedDigest(PCRTASN1OBJID pAlgorithm, PCRTASN1DYNTYPE pParameters, PCRTASN1BITSTRING pPublicKey,
186 void const *pvSignedDigest, size_t cbSignedDigest, RTCRDIGEST hDigest,
187 PRTERRINFO pErrInfo)
188{
189 /*
190 * Valid input.
191 */
192 AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER);
193 AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER);
194
195 if (pParameters)
196 {
197 AssertPtrReturn(pParameters, VERR_INVALID_POINTER);
198 if (pParameters->enmType == RTASN1TYPE_NULL)
199 pParameters = NULL;
200 }
201
202 AssertPtrReturn(pPublicKey, VERR_INVALID_POINTER);
203 AssertReturn(RTAsn1BitString_IsPresent(pPublicKey), VERR_INVALID_POINTER);
204
205 AssertPtrReturn(pvSignedDigest, VERR_INVALID_POINTER);
206 AssertReturn(cbSignedDigest, VERR_INVALID_PARAMETER);
207
208 AssertPtrReturn(hDigest, VERR_INVALID_HANDLE);
209
210 /*
211 * Parameters are not currently supported (openssl code path).
212 */
213 if (pParameters)
214 return RTErrInfoSet(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL,
215 "Cipher algorithm parameters are not yet supported.");
216
217 /*
218 * Validate using IPRT.
219 */
220 RTCRPKIXSIGNATURE hSignature;
221 int rcIprt = RTCrPkixSignatureCreateByObjId(&hSignature, pAlgorithm, false /*fSigning*/, pPublicKey, pParameters);
222 if (RT_FAILURE(rcIprt))
223 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN,
224 "Unknown public key algorithm [IPRT]: %s", pAlgorithm->szObjId);
225
226 rcIprt = RTCrPkixSignatureVerify(hSignature, hDigest, pvSignedDigest, cbSignedDigest);
227 if (RT_FAILURE(rcIprt))
228 RTErrInfoSet(pErrInfo, rcIprt, "RTCrPkixSignatureVerifyBitString failed");
229
230 RTCrPkixSignatureRelease(hSignature);
231
232#if defined(IPRT_WITH_OPENSSL) \
233 && (OPENSSL_VERSION_NUMBER > 0x10000000L) /* 0.9.8 doesn't seem to have EVP_PKEY_CTX_set_signature_md. */
234 /*
235 * Validate using OpenSSL EVP.
236 */
237 rtCrOpenSslInit();
238
239 const char *pszAlgObjId = pAlgorithm->szObjId;
240 if (!strcmp(pszAlgObjId, RTCRX509ALGORITHMIDENTIFIERID_RSA))
241 {
242 pszAlgObjId = RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid(pszAlgObjId,
243 RTCrDigestGetAlgorithmOid(hDigest));
244 AssertMsgStmt(pszAlgObjId, ("enc=%s hash=%s\n", pAlgorithm->szObjId, RTCrDigestGetAlgorithmOid(hDigest)),
245 pszAlgObjId = RTCrDigestGetAlgorithmOid(hDigest));
246 }
247
248 /* Translate the algorithm ID into a EVP message digest type pointer. */
249 int iAlgoNid = OBJ_txt2nid(pszAlgObjId);
250 if (iAlgoNid == NID_undef)
251 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN,
252 "Unknown public key algorithm [OpenSSL]: %s", pszAlgObjId);
253 const char *pszAlogSn = OBJ_nid2sn(iAlgoNid);
254 const EVP_MD *pEvpMdType = EVP_get_digestbyname(pszAlogSn);
255 if (!pEvpMdType)
256 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP,
257 "EVP_get_digestbyname failed on %s (%s)", pszAlogSn, pszAlgObjId);
258
259 /* Create an EVP public key. */
260 int rcOssl;
261 EVP_PKEY *pEvpPublicKey = EVP_PKEY_new();
262 if (pEvpPublicKey)
263 {
264 pEvpPublicKey->type = EVP_PKEY_type(pEvpMdType->required_pkey_type[0]);
265 if (pEvpPublicKey->type != NID_undef)
266 {
267 const unsigned char *puchPublicKey = RTASN1BITSTRING_GET_BIT0_PTR(pPublicKey);
268 if (d2i_PublicKey(pEvpPublicKey->type, &pEvpPublicKey, &puchPublicKey, RTASN1BITSTRING_GET_BYTE_SIZE(pPublicKey)))
269 {
270 /* Create an EVP public key context we can use to validate the digest. */
271 EVP_PKEY_CTX *pEvpPKeyCtx = EVP_PKEY_CTX_new(pEvpPublicKey, NULL);
272 if (pEvpPKeyCtx)
273 {
274 rcOssl = EVP_PKEY_verify_init(pEvpPKeyCtx);
275 if (rcOssl > 0)
276 {
277 rcOssl = EVP_PKEY_CTX_set_signature_md(pEvpPKeyCtx, pEvpMdType);
278 if (rcOssl > 0)
279 {
280 /* Get the digest from hDigest and verify it. */
281 rcOssl = EVP_PKEY_verify(pEvpPKeyCtx,
282 (uint8_t const *)pvSignedDigest,
283 cbSignedDigest,
284 RTCrDigestGetHash(hDigest),
285 RTCrDigestGetHashSize(hDigest));
286 if (rcOssl > 0)
287 rcOssl = VINF_SUCCESS;
288 else
289 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED,
290 "EVP_PKEY_verify failed (%d)", rcOssl);
291 }
292 else
293 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
294 "EVP_PKEY_CTX_set_signature_md failed (%d)", rcOssl);
295 }
296 else
297 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
298 "EVP_PKEY_verify_init failed (%d)", rcOssl);
299 EVP_PKEY_CTX_free(pEvpPKeyCtx);
300 }
301 else
302 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_CTX_new failed");
303 }
304 else
305 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_D2I_PUBLIC_KEY_FAILED, "d2i_PublicKey failed");
306 }
307 else
308 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
309 "EVP_PKEY_type(%d) failed", pEvpMdType->required_pkey_type[0]);
310 /* Cleanup and return.*/
311 EVP_PKEY_free(pEvpPublicKey);
312 }
313 else
314 rcOssl = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "EVP_PKEY_new(%d) failed", pEvpMdType->required_pkey_type[0]);
315
316 /*
317 * Check the result.
318 */
319 if (RT_SUCCESS(rcIprt) && RT_SUCCESS(rcOssl))
320 return VINF_SUCCESS;
321 if (RT_FAILURE_NP(rcIprt) && RT_FAILURE_NP(rcOssl))
322 return rcIprt;
323 AssertMsgFailed(("rcIprt=%Rrc rcOssl=%Rrc\n", rcIprt, rcOssl));
324 if (RT_FAILURE_NP(rcOssl))
325 return rcOssl;
326#endif /* IPRT_WITH_OPENSSL */
327
328 return rcIprt;
329}
330
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