VirtualBox

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

Last change on this file since 73705 was 73705, checked in by vboxsync, 6 years ago

IPRT: Better fix for missing md4 failure; adding information status codes for indicating deprecated and compromised digests when used.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.3 KB
Line 
1/* $Id: pkix-verify.cpp 73705 2018-08-16 09:31:18Z 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#include <iprt/crypto/key.h>
38
39#ifdef IPRT_WITH_OPENSSL
40# include "internal/iprt-openssl.h"
41# include "openssl/evp.h"
42# ifndef OPENSSL_VERSION_NUMBER
43# error "Missing OPENSSL_VERSION_NUMBER!"
44# endif
45#endif
46
47
48
49RTDECL(int) RTCrPkixPubKeyVerifySignature(PCRTASN1OBJID pAlgorithm, RTCRKEY hPublicKey, PCRTASN1DYNTYPE pParameters,
50 PCRTASN1BITSTRING pSignatureValue, const void *pvData, size_t cbData,
51 PRTERRINFO pErrInfo)
52{
53 /*
54 * Valid input.
55 */
56 AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER);
57 AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER);
58
59 if (pParameters)
60 {
61 AssertPtrReturn(pParameters, VERR_INVALID_POINTER);
62 if (pParameters->enmType == RTASN1TYPE_NULL)
63 pParameters = NULL;
64 }
65
66 AssertPtrReturn(hPublicKey, VERR_INVALID_POINTER);
67 Assert(RTCrKeyHasPublicPart(hPublicKey));
68
69 AssertPtrReturn(pSignatureValue, VERR_INVALID_POINTER);
70 AssertReturn(RTAsn1BitString_IsPresent(pSignatureValue), VERR_INVALID_POINTER);
71
72 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
73 AssertReturn(cbData > 0, VERR_INVALID_PARAMETER);
74
75 /*
76 * Parameters are not currently supported (openssl code path).
77 */
78 if (pParameters)
79 return RTErrInfoSet(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL,
80 "Cipher algorithm parameters are not yet supported.");
81
82 /*
83 * Validate using IPRT.
84 */
85 RTCRPKIXSIGNATURE hSignature;
86 int rcIprt = RTCrPkixSignatureCreateByObjId(&hSignature, pAlgorithm, hPublicKey, pParameters, false /*fSigning*/);
87 if (RT_FAILURE(rcIprt))
88 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN,
89 "Unknown public key algorithm [IPRT]: %s", pAlgorithm->szObjId);
90
91 RTCRDIGEST hDigest;
92 rcIprt = RTCrDigestCreateByObjId(&hDigest, pAlgorithm);
93 if (RT_SUCCESS(rcIprt))
94 {
95 /* Calculate the digest. */
96 rcIprt = RTCrDigestUpdate(hDigest, pvData, cbData);
97 if (RT_SUCCESS(rcIprt))
98 {
99 rcIprt = RTCrPkixSignatureVerifyBitString(hSignature, hDigest, pSignatureValue);
100 if (RT_FAILURE(rcIprt))
101 RTErrInfoSet(pErrInfo, rcIprt, "RTCrPkixSignatureVerifyBitString failed");
102 }
103 else
104 RTErrInfoSet(pErrInfo, rcIprt, "RTCrDigestUpdate failed");
105 RTCrDigestRelease(hDigest);
106 }
107 else
108 RTErrInfoSetF(pErrInfo, rcIprt, "Unknown digest algorithm [IPRT]: %s", pAlgorithm->szObjId);
109 RTCrPkixSignatureRelease(hSignature);
110
111#ifdef IPRT_WITH_OPENSSL
112 /*
113 * Validate using OpenSSL EVP.
114 */
115 /* Create an EVP public key. */
116 EVP_PKEY *pEvpPublicKey = NULL;
117 const EVP_MD *pEvpMdType = NULL;
118 int rcOssl = rtCrKeyToOpenSslKey(hPublicKey, true /*fNeedPublic*/, pAlgorithm->szObjId,
119 (void **)&pEvpPublicKey, (const void **)&pEvpMdType, pErrInfo);
120 if (RT_SUCCESS(rcOssl))
121 {
122 EVP_MD_CTX *pEvpMdCtx = EVP_MD_CTX_create();
123 if (pEvpMdCtx)
124 {
125 if (EVP_VerifyInit_ex(pEvpMdCtx, pEvpMdType, NULL /*engine*/))
126 {
127 /* Digest the data. */
128 EVP_VerifyUpdate(pEvpMdCtx, pvData, cbData);
129
130 /* Verify the signature. */
131 if (EVP_VerifyFinal(pEvpMdCtx,
132 RTASN1BITSTRING_GET_BIT0_PTR(pSignatureValue),
133 RTASN1BITSTRING_GET_BYTE_SIZE(pSignatureValue),
134 pEvpPublicKey) > 0)
135 rcOssl = VINF_SUCCESS;
136 else
137 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED, "EVP_VerifyFinal failed");
138
139 /* Cleanup and return: */
140 }
141 else
142 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_CIPHER_ALOG_INIT_FAILED,
143 "EVP_VerifyInit_ex failed (algorithm type is %s)", pAlgorithm->szObjId);
144 EVP_MD_CTX_destroy(pEvpMdCtx);
145 }
146 else
147 rcOssl = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "EVP_MD_CTX_create failed");
148 EVP_PKEY_free(pEvpPublicKey);
149 }
150
151 /*
152 * Check the result.
153 */
154 if ( RT_SUCCESS(rcIprt) && RT_SUCCESS(rcOssl)
155 || (RT_FAILURE_NP(rcIprt) && RT_FAILURE_NP(rcOssl))
156 || (RT_SUCCESS(rcIprt) && rcOssl == VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP) )
157 return rcIprt;
158 AssertMsgFailed(("rcIprt=%Rrc rcOssl=%Rrc\n", rcIprt, rcOssl));
159 if (RT_FAILURE_NP(rcOssl))
160 return rcOssl;
161#endif /* IPRT_WITH_OPENSSL */
162
163 return rcIprt;
164}
165
166
167RTDECL(int) RTCrPkixPubKeyVerifySignedDigest(PCRTASN1OBJID pAlgorithm, RTCRKEY hPublicKey, PCRTASN1DYNTYPE pParameters,
168 void const *pvSignedDigest, size_t cbSignedDigest, RTCRDIGEST hDigest,
169 PRTERRINFO pErrInfo)
170{
171 /*
172 * Valid input.
173 */
174 AssertPtrReturn(pAlgorithm, VERR_INVALID_POINTER);
175 AssertReturn(RTAsn1ObjId_IsPresent(pAlgorithm), VERR_INVALID_POINTER);
176
177 if (pParameters)
178 {
179 AssertPtrReturn(pParameters, VERR_INVALID_POINTER);
180 if (pParameters->enmType == RTASN1TYPE_NULL)
181 pParameters = NULL;
182 }
183
184 AssertPtrReturn(hPublicKey, VERR_INVALID_POINTER);
185 Assert(RTCrKeyHasPublicPart(hPublicKey));
186
187 AssertPtrReturn(pvSignedDigest, VERR_INVALID_POINTER);
188 AssertReturn(cbSignedDigest, VERR_INVALID_PARAMETER);
189
190 AssertPtrReturn(hDigest, VERR_INVALID_HANDLE);
191
192 /*
193 * Parameters are not currently supported (openssl code path).
194 */
195 if (pParameters)
196 return RTErrInfoSet(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_PARAMS_NOT_IMPL,
197 "Cipher algorithm parameters are not yet supported.");
198
199 /*
200 * Validate using IPRT.
201 */
202 RTCRPKIXSIGNATURE hSignature;
203 int rcIprt = RTCrPkixSignatureCreateByObjId(&hSignature, pAlgorithm, hPublicKey, pParameters, false /*fSigning*/);
204 if (RT_FAILURE(rcIprt))
205 return RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_CIPHER_ALGO_NOT_KNOWN,
206 "Unknown public key algorithm [IPRT]: %s", pAlgorithm->szObjId);
207
208 rcIprt = RTCrPkixSignatureVerify(hSignature, hDigest, pvSignedDigest, cbSignedDigest);
209 if (RT_FAILURE(rcIprt))
210 RTErrInfoSet(pErrInfo, rcIprt, "RTCrPkixSignatureVerifyBitString failed");
211
212 RTCrPkixSignatureRelease(hSignature);
213
214#if defined(IPRT_WITH_OPENSSL) \
215 && (OPENSSL_VERSION_NUMBER > 0x10000000L) /* 0.9.8 doesn't seem to have EVP_PKEY_CTX_set_signature_md. */
216 /*
217 * Validate using OpenSSL EVP.
218 */
219 /* Combine encryption and digest if the algorithm doesn't specify the digest type. */
220 const char *pszAlgObjId = pAlgorithm->szObjId;
221 if (!strcmp(pszAlgObjId, RTCRX509ALGORITHMIDENTIFIERID_RSA))
222 {
223 pszAlgObjId = RTCrX509AlgorithmIdentifier_CombineEncryptionOidAndDigestOid(pszAlgObjId,
224 RTCrDigestGetAlgorithmOid(hDigest));
225 AssertMsgStmt(pszAlgObjId, ("enc=%s hash=%s\n", pAlgorithm->szObjId, RTCrDigestGetAlgorithmOid(hDigest)),
226 pszAlgObjId = RTCrDigestGetAlgorithmOid(hDigest));
227 }
228
229 /* Create an EVP public key. */
230 EVP_PKEY *pEvpPublicKey = NULL;
231 const EVP_MD *pEvpMdType = NULL;
232 int rcOssl = rtCrKeyToOpenSslKey(hPublicKey, true /*fNeedPublic*/, pszAlgObjId,
233 (void **)&pEvpPublicKey, (const void **)&pEvpMdType, pErrInfo);
234 if (RT_SUCCESS(rcOssl))
235 {
236 /* Create an EVP public key context we can use to validate the digest. */
237 EVP_PKEY_CTX *pEvpPKeyCtx = EVP_PKEY_CTX_new(pEvpPublicKey, NULL);
238 if (pEvpPKeyCtx)
239 {
240 rcOssl = EVP_PKEY_verify_init(pEvpPKeyCtx);
241 if (rcOssl > 0)
242 {
243 rcOssl = EVP_PKEY_CTX_set_signature_md(pEvpPKeyCtx, pEvpMdType);
244 if (rcOssl > 0)
245 {
246 /* Get the digest from hDigest and verify it. */
247 rcOssl = EVP_PKEY_verify(pEvpPKeyCtx,
248 (uint8_t const *)pvSignedDigest,
249 cbSignedDigest,
250 RTCrDigestGetHash(hDigest),
251 RTCrDigestGetHashSize(hDigest));
252 if (rcOssl > 0)
253 rcOssl = VINF_SUCCESS;
254 else
255 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_VERIFY_FINAL_FAILED,
256 "EVP_PKEY_verify failed (%d)", rcOssl);
257 /* Cleanup and return: */
258 }
259 else
260 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
261 "EVP_PKEY_CTX_set_signature_md failed (%d)", rcOssl);
262 }
263 else
264 rcOssl = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR,
265 "EVP_PKEY_verify_init failed (%d)", rcOssl);
266 EVP_PKEY_CTX_free(pEvpPKeyCtx);
267 }
268 else
269 rcOssl = RTErrInfoSet(pErrInfo, VERR_CR_PKIX_OSSL_EVP_PKEY_TYPE_ERROR, "EVP_PKEY_CTX_new failed");
270 EVP_PKEY_free(pEvpPublicKey);
271 }
272
273 /*
274 * Check the result.
275 */
276 if ( RT_SUCCESS(rcIprt) && RT_SUCCESS(rcOssl)
277 || (RT_FAILURE_NP(rcIprt) && RT_FAILURE_NP(rcOssl))
278 || (RT_SUCCESS(rcIprt) && rcOssl == VERR_CR_PKIX_OSSL_CIPHER_ALGO_NOT_KNOWN_EVP) )
279 return rcIprt;
280 AssertMsgFailed(("rcIprt=%Rrc rcOssl=%Rrc\n", rcIprt, rcOssl));
281 if (RT_FAILURE_NP(rcOssl))
282 return rcOssl;
283#endif /* IPRT_WITH_OPENSSL */
284
285 return rcIprt;
286}
287
288
289RTDECL(int) RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo(PCRTCRX509SUBJECTPUBLICKEYINFO pCertPubKeyInfo,
290 void const *pvSignedDigest, size_t cbSignedDigest,
291 RTCRDIGEST hDigest, PRTERRINFO pErrInfo)
292{
293 RTCRKEY hPublicKey;
294 int rc = RTCrKeyCreateFromPublicAlgorithmAndBits(&hPublicKey, &pCertPubKeyInfo->Algorithm.Algorithm,
295 &pCertPubKeyInfo->SubjectPublicKey, pErrInfo, NULL);
296 if (RT_SUCCESS(rc))
297 {
298 rc = RTCrPkixPubKeyVerifySignedDigest(&pCertPubKeyInfo->Algorithm.Algorithm, hPublicKey,
299 &pCertPubKeyInfo->Algorithm.Parameters, pvSignedDigest, cbSignedDigest,
300 hDigest, pErrInfo);
301
302 uint32_t cRefs = RTCrKeyRelease(hPublicKey);
303 Assert(cRefs == 0); RT_NOREF(cRefs);
304 }
305 return rc;
306}
307
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