VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/digest-core.cpp@ 96858

Last change on this file since 96858 was 96858, checked in by vboxsync, 2 years ago

IPRT/RTCrDigestFinal: Corrected underflow (warning) / overflow (error) mixup. bugref:10287

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1/* $Id: digest-core.cpp 96858 2022-09-26 09:25:03Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - Cryptographic Hash / Message Digest API
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/crypto/digest.h>
43
44#include <iprt/asm.h>
45#include <iprt/err.h>
46#include <iprt/mem.h>
47#include <iprt/string.h>
48#include <iprt/crypto/x509.h>
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54/**
55 * Generic message digest instance.
56 */
57typedef struct RTCRDIGESTINT
58{
59 /** Magic value (RTCRDIGESTINT_MAGIC). */
60 uint32_t u32Magic;
61 /** Reference counter. */
62 uint32_t volatile cRefs;
63 /** Pointer to the message digest descriptor. */
64 PCRTCRDIGESTDESC pDesc;
65 /** The offset into abState of the storage space . At
66 * least RTCRDIGESTDESC::cbHash bytes is available at that location. */
67 uint32_t offHash;
68 /** State. */
69 uint32_t uState;
70 /** The number of bytes consumed. */
71 uint64_t cbConsumed;
72 /** Pointer to the data specific to the message digest algorithm. Points
73 * either to &abState[0] or to memory allocated with pDesc->pfnNew. */
74 void *pvState;
75 /** Opaque data specific to the message digest algorithm, size given by
76 * RTCRDIGESTDESC::cbState. This is followed by space for the final hash
77 * at offHash with size RTCRDIGESTDESC::cbHash. The data specific to the
78 * message digest algorithm can also be 0. In this case, pDesc->pfnNew()
79 * and pDesc->pfnFree() must not be NULL. */
80 uint8_t abState[1];
81} RTCRDIGESTINT;
82/** Pointer to a message digest instance. */
83typedef RTCRDIGESTINT *PRTCRDIGESTINT;
84
85/** Magic value for RTCRDIGESTINT::u32Magic (Ralph C. Merkle). */
86#define RTCRDIGESTINT_MAGIC UINT32_C(0x19520202)
87
88/** @name RTCRDIGESTINT::uState values.
89 * @{ */
90/** Ready for more data. */
91#define RTCRDIGEST_STATE_READY UINT32_C(1)
92/** The hash has been finalized and can be found at offHash. */
93#define RTCRDIGEST_STATE_FINAL UINT32_C(2)
94/** Busted state, can happen after re-init. */
95#define RTCRDIGEST_STATE_BUSTED UINT32_C(3)
96/** @} */
97
98
99
100/**
101 * Used for successful returns which wants to hit at digest security.
102 *
103 * @retval VINF_SUCCESS
104 * @retval VINF_CR_DIGEST_DEPRECATED
105 * @retval VINF_CR_DIGEST_COMPROMISED
106 * @retval VINF_CR_DIGEST_SEVERELY_COMPROMISED
107 * @param pDesc The digest descriptor.
108 */
109DECLINLINE(int) rtCrDigestSuccessWithDigestWarnings(PCRTCRDIGESTDESC pDesc)
110{
111 uint32_t const fFlags = pDesc->fFlags
112 & (RTCRDIGESTDESC_F_DEPRECATED | RTCRDIGESTDESC_F_COMPROMISED | RTCRDIGESTDESC_F_SERVERELY_COMPROMISED);
113 if (!fFlags)
114 return VINF_SUCCESS;
115 if (fFlags & RTCRDIGESTDESC_F_SERVERELY_COMPROMISED)
116 return VINF_CR_DIGEST_SEVERELY_COMPROMISED;
117 if (fFlags & RTCRDIGESTDESC_F_COMPROMISED)
118 return VINF_CR_DIGEST_COMPROMISED;
119 return VINF_CR_DIGEST_DEPRECATED;
120}
121
122
123RTDECL(int) RTCrDigestCreate(PRTCRDIGEST phDigest, PCRTCRDIGESTDESC pDesc, void *pvOpaque)
124{
125 AssertPtrReturn(phDigest, VERR_INVALID_POINTER);
126 AssertPtrReturn(pDesc, VERR_INVALID_POINTER);
127
128 int rc = VINF_SUCCESS;
129 uint32_t const offHash = RT_ALIGN_32(pDesc->cbState, 8);
130 AssertReturn(pDesc->pfnNew || offHash, VERR_INVALID_PARAMETER);
131 AssertReturn(!pDesc->pfnNew || (pDesc->pfnFree && pDesc->pfnInit && pDesc->pfnClone), VERR_INVALID_PARAMETER);
132 PRTCRDIGESTINT pThis = (PRTCRDIGESTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCRDIGESTINT, abState[offHash + pDesc->cbHash]));
133 if (pThis)
134 {
135 if (pDesc->pfnNew)
136 pThis->pvState = pDesc->pfnNew();
137 else
138 pThis->pvState = &pThis->abState[0];
139 if (pThis->pvState)
140 {
141 pThis->u32Magic = RTCRDIGESTINT_MAGIC;
142 pThis->cRefs = 1;
143 pThis->offHash = offHash;
144 pThis->pDesc = pDesc;
145 pThis->uState = RTCRDIGEST_STATE_READY;
146 if (pDesc->pfnInit)
147 rc = pDesc->pfnInit(pThis->pvState, pvOpaque, false /*fReInit*/);
148 if (RT_SUCCESS(rc))
149 {
150 *phDigest = pThis;
151 return rtCrDigestSuccessWithDigestWarnings(pDesc);
152 }
153 if (pDesc->pfnFree)
154 pDesc->pfnFree(pThis->pvState);
155 }
156 else
157 rc = VERR_NO_MEMORY;
158 pThis->u32Magic = 0;
159 RTMemFree(pThis);
160 }
161 else
162 rc = VERR_NO_MEMORY;
163 return rc;
164}
165
166
167RTDECL(int) RTCrDigestClone(PRTCRDIGEST phDigest, RTCRDIGEST hSrc)
168{
169 AssertPtrReturn(phDigest, VERR_INVALID_POINTER);
170 AssertPtrReturn(hSrc, VERR_INVALID_HANDLE);
171 AssertReturn(hSrc->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
172
173 int rc = VINF_SUCCESS;
174 uint32_t const offHash = hSrc->offHash;
175 PRTCRDIGESTINT pThis = (PRTCRDIGESTINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCRDIGESTINT, abState[offHash + hSrc->pDesc->cbHash]));
176 if (pThis)
177 {
178 if (hSrc->pDesc->pfnNew)
179 pThis->pvState = hSrc->pDesc->pfnNew();
180 else
181 pThis->pvState = &pThis->abState[0];
182 if (pThis->pvState)
183 {
184 pThis->u32Magic = RTCRDIGESTINT_MAGIC;
185 pThis->cRefs = 1;
186 pThis->offHash = offHash;
187 pThis->pDesc = hSrc->pDesc;
188 if (hSrc->pDesc->pfnClone)
189 rc = hSrc->pDesc->pfnClone(pThis->pvState, hSrc->pvState);
190 else
191 {
192 Assert(!hSrc->pDesc->pfnNew);
193 memcpy(pThis->pvState, hSrc->pvState, offHash);
194 }
195 memcpy(&pThis->abState[offHash], &hSrc->abState[offHash], hSrc->pDesc->cbHash);
196 pThis->uState = hSrc->uState;
197
198 if (RT_SUCCESS(rc))
199 {
200 *phDigest = pThis;
201 return rtCrDigestSuccessWithDigestWarnings(pThis->pDesc);
202 }
203 if (hSrc->pDesc->pfnFree)
204 hSrc->pDesc->pfnFree(pThis->pvState);
205 }
206 else
207 rc = VERR_NO_MEMORY;
208 pThis->u32Magic = 0;
209 RTMemFree(pThis);
210 }
211 else
212 rc = VERR_NO_MEMORY;
213 return rc;
214}
215
216
217RTDECL(int) RTCrDigestReset(RTCRDIGEST hDigest)
218{
219 PRTCRDIGESTINT pThis = hDigest;
220 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
221 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
222
223 pThis->cbConsumed = 0;
224 pThis->uState = RTCRDIGEST_STATE_READY;
225
226 int rc = VINF_SUCCESS;
227 if (pThis->pDesc->pfnInit)
228 {
229 rc = pThis->pDesc->pfnInit(pThis->pvState, NULL, true /*fReInit*/);
230 if (RT_FAILURE(rc))
231 pThis->uState = RTCRDIGEST_STATE_BUSTED;
232 RT_BZERO(&pThis->abState[pThis->offHash], pThis->pDesc->cbHash);
233 }
234 else
235 {
236 Assert(!pThis->pDesc->pfnNew);
237 RT_BZERO(pThis->pvState, pThis->offHash + pThis->pDesc->cbHash);
238 }
239 return rc;
240}
241
242
243RTDECL(uint32_t) RTCrDigestRetain(RTCRDIGEST hDigest)
244{
245 PRTCRDIGESTINT pThis = hDigest;
246 AssertPtrReturn(pThis, UINT32_MAX);
247 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, UINT32_MAX);
248
249 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
250 Assert(cRefs < 64);
251 return cRefs;
252}
253
254
255RTDECL(uint32_t) RTCrDigestRelease(RTCRDIGEST hDigest)
256{
257 PRTCRDIGESTINT pThis = hDigest;
258 if (pThis == NIL_RTCRDIGEST)
259 return 0;
260 AssertPtrReturn(pThis, UINT32_MAX);
261 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, UINT32_MAX);
262
263 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
264 if (!cRefs)
265 {
266 pThis->u32Magic = ~RTCRDIGESTINT_MAGIC;
267 if (pThis->pDesc->pfnDelete)
268 pThis->pDesc->pfnDelete(pThis->pvState);
269 if (pThis->pDesc->pfnFree)
270 pThis->pDesc->pfnFree(pThis->pvState);
271 RTMemFree(pThis);
272 }
273 Assert(cRefs < 64);
274 return cRefs;
275}
276
277
278RTDECL(int) RTCrDigestUpdate(RTCRDIGEST hDigest, void const *pvData, size_t cbData)
279{
280 PRTCRDIGESTINT pThis = hDigest;
281 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
282 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
283 AssertReturn(pThis->uState == RTCRDIGEST_STATE_READY, VERR_INVALID_STATE);
284
285 pThis->pDesc->pfnUpdate(pThis->pvState, pvData, cbData);
286 pThis->cbConsumed += cbData;
287 return VINF_SUCCESS;
288}
289
290
291RTDECL(int) RTCrDigestFinal(RTCRDIGEST hDigest, void *pvHash, size_t cbHash)
292{
293 PRTCRDIGESTINT pThis = hDigest;
294 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
295 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, VERR_INVALID_HANDLE);
296 AssertReturn(pThis->uState == RTCRDIGEST_STATE_READY || pThis->uState == RTCRDIGEST_STATE_FINAL, VERR_INVALID_STATE);
297 AssertPtrNullReturn(pvHash, VERR_INVALID_POINTER);
298
299 /*
300 * Make sure the hash calculation is final.
301 */
302 if (pThis->uState == RTCRDIGEST_STATE_READY)
303 {
304 pThis->pDesc->pfnFinal(pThis->pvState, &pThis->abState[pThis->offHash]);
305 pThis->uState = RTCRDIGEST_STATE_FINAL;
306 }
307 else
308 AssertReturn(pThis->uState == RTCRDIGEST_STATE_FINAL, VERR_INVALID_STATE);
309
310 /*
311 * Copy out the hash if requested.
312 */
313 if (cbHash > 0)
314 {
315 uint32_t cbNeeded = pThis->pDesc->cbHash;
316 if (pThis->pDesc->pfnGetHashSize)
317 cbNeeded = pThis->pDesc->pfnGetHashSize(pThis->pvState);
318 Assert(cbNeeded > 0);
319
320 if (cbNeeded == cbHash)
321 memcpy(pvHash, &pThis->abState[pThis->offHash], cbNeeded);
322 else if (cbNeeded < cbHash)
323 {
324 memcpy(pvHash, &pThis->abState[pThis->offHash], cbNeeded);
325 memset((uint8_t *)pvHash + cbNeeded, 0, cbHash - cbNeeded);
326 return VINF_BUFFER_UNDERFLOW;
327 }
328 else
329 {
330 memcpy(pvHash, &pThis->abState[pThis->offHash], cbHash);
331 return VERR_BUFFER_OVERFLOW;
332 }
333 }
334
335 return rtCrDigestSuccessWithDigestWarnings(pThis->pDesc);
336}
337
338
339RTDECL(bool) RTCrDigestMatch(RTCRDIGEST hDigest, void const *pvHash, size_t cbHash)
340{
341 PRTCRDIGESTINT pThis = hDigest;
342
343 int rc = RTCrDigestFinal(pThis, NULL, 0);
344 AssertRCReturn(rc, false);
345
346 AssertPtrReturn(pvHash, false);
347 return pThis->pDesc->cbHash == cbHash
348 && !memcmp(&pThis->abState[pThis->offHash], pvHash, cbHash);
349}
350
351
352RTDECL(uint8_t const *) RTCrDigestGetHash(RTCRDIGEST hDigest)
353{
354 PRTCRDIGESTINT pThis = hDigest;
355 AssertPtrReturn(pThis, NULL);
356 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, NULL);
357
358 int rc = RTCrDigestFinal(pThis, NULL, 0);
359 AssertRCReturn(rc, NULL);
360
361 return &pThis->abState[pThis->offHash];
362}
363
364
365RTDECL(uint32_t) RTCrDigestGetHashSize(RTCRDIGEST hDigest)
366{
367 PRTCRDIGESTINT pThis = hDigest;
368 AssertPtrReturn(pThis, 0);
369 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, 0);
370 if (pThis->pDesc->pfnGetHashSize)
371 {
372 uint32_t cbHash = pThis->pDesc->pfnGetHashSize(pThis->pvState);
373 Assert(cbHash <= pThis->pDesc->cbHash);
374 return cbHash;
375 }
376 return pThis->pDesc->cbHash;
377}
378
379
380RTDECL(uint64_t) RTCrDigestGetConsumedSize(RTCRDIGEST hDigest)
381{
382 PRTCRDIGESTINT pThis = hDigest;
383 AssertPtrReturn(pThis, 0);
384 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, 0);
385 return pThis->cbConsumed;
386}
387
388
389RTDECL(bool) RTCrDigestIsFinalized(RTCRDIGEST hDigest)
390{
391 PRTCRDIGESTINT pThis = hDigest;
392 AssertPtrReturn(pThis, false);
393 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, false);
394 return pThis->uState == RTCRDIGEST_STATE_FINAL;
395}
396
397
398RTDECL(RTDIGESTTYPE) RTCrDigestGetType(RTCRDIGEST hDigest)
399{
400 PRTCRDIGESTINT pThis = hDigest;
401 AssertPtrReturn(pThis, RTDIGESTTYPE_INVALID);
402 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, RTDIGESTTYPE_INVALID);
403
404 RTDIGESTTYPE enmType = pThis->pDesc->enmType;
405 if (pThis->pDesc->pfnGetDigestType)
406 enmType = pThis->pDesc->pfnGetDigestType(pThis->pvState);
407 return enmType;
408}
409
410
411RTDECL(const char *) RTCrDigestGetAlgorithmOid(RTCRDIGEST hDigest)
412{
413 return RTCrDigestTypeToAlgorithmOid(RTCrDigestGetType(hDigest));
414}
415
416
417RTDECL(uint32_t) RTCrDigestGetFlags(RTCRDIGEST hDigest)
418{
419 PRTCRDIGESTINT pThis = hDigest;
420 AssertPtrReturn(pThis, UINT32_MAX);
421 AssertReturn(pThis->u32Magic == RTCRDIGESTINT_MAGIC, UINT32_MAX);
422 return pThis->pDesc->fFlags;
423}
424
425
426RTDECL(const char *) RTCrDigestTypeToAlgorithmOid(RTDIGESTTYPE enmDigestType)
427{
428 switch (enmDigestType)
429 {
430 case RTDIGESTTYPE_MD2: return RTCRX509ALGORITHMIDENTIFIERID_MD2;
431 case RTDIGESTTYPE_MD4: return RTCRX509ALGORITHMIDENTIFIERID_MD4;
432 case RTDIGESTTYPE_MD5: return RTCRX509ALGORITHMIDENTIFIERID_MD5;
433 case RTDIGESTTYPE_SHA1: return RTCRX509ALGORITHMIDENTIFIERID_SHA1;
434 case RTDIGESTTYPE_SHA224: return RTCRX509ALGORITHMIDENTIFIERID_SHA224;
435 case RTDIGESTTYPE_SHA256: return RTCRX509ALGORITHMIDENTIFIERID_SHA256;
436 case RTDIGESTTYPE_SHA384: return RTCRX509ALGORITHMIDENTIFIERID_SHA384;
437 case RTDIGESTTYPE_SHA512: return RTCRX509ALGORITHMIDENTIFIERID_SHA512;
438 case RTDIGESTTYPE_SHA512T224: return RTCRX509ALGORITHMIDENTIFIERID_SHA512T224;
439 case RTDIGESTTYPE_SHA512T256: return RTCRX509ALGORITHMIDENTIFIERID_SHA512T256;
440 case RTDIGESTTYPE_SHA3_224: return RTCRX509ALGORITHMIDENTIFIERID_SHA3_224;
441 case RTDIGESTTYPE_SHA3_256: return RTCRX509ALGORITHMIDENTIFIERID_SHA3_256;
442 case RTDIGESTTYPE_SHA3_384: return RTCRX509ALGORITHMIDENTIFIERID_SHA3_384;
443 case RTDIGESTTYPE_SHA3_512: return RTCRX509ALGORITHMIDENTIFIERID_SHA3_512;
444 default: return NULL;
445 }
446}
447
448
449RTDECL(const char *) RTCrDigestTypeToName(RTDIGESTTYPE enmDigestType)
450{
451 switch (enmDigestType)
452 {
453 case RTDIGESTTYPE_CRC32: return "CRC32";
454 case RTDIGESTTYPE_CRC64: return "CRC64";
455 case RTDIGESTTYPE_MD2: return "MD2";
456 case RTDIGESTTYPE_MD4: return "MD4";
457 case RTDIGESTTYPE_MD5: return "MD5";
458 case RTDIGESTTYPE_SHA1: return "SHA-1";
459 case RTDIGESTTYPE_SHA224: return "SHA-224";
460 case RTDIGESTTYPE_SHA256: return "SHA-256";
461 case RTDIGESTTYPE_SHA384: return "SHA-384";
462 case RTDIGESTTYPE_SHA512: return "SHA-512";
463 case RTDIGESTTYPE_SHA512T224: return "SHA-512/224";
464 case RTDIGESTTYPE_SHA512T256: return "SHA-512/256";
465 case RTDIGESTTYPE_SHA3_224: return "SHA3-224";
466 case RTDIGESTTYPE_SHA3_256: return "SHA3-256";
467 case RTDIGESTTYPE_SHA3_384: return "SHA3-384";
468 case RTDIGESTTYPE_SHA3_512: return "SHA3-512";
469 default: return NULL;
470 }
471}
472
473
474RTDECL(uint32_t) RTCrDigestTypeToHashSize(RTDIGESTTYPE enmDigestType)
475{
476 switch (enmDigestType)
477 {
478 case RTDIGESTTYPE_CRC32: return 32 / 8;
479 case RTDIGESTTYPE_CRC64: return 64 / 8;
480 case RTDIGESTTYPE_MD2: return 128 / 8;
481 case RTDIGESTTYPE_MD4: return 128 / 8;
482 case RTDIGESTTYPE_MD5: return 128 / 8;
483 case RTDIGESTTYPE_SHA1: return 160 / 8;
484 case RTDIGESTTYPE_SHA224: return 224 / 8;
485 case RTDIGESTTYPE_SHA256: return 256 / 8;
486 case RTDIGESTTYPE_SHA384: return 384 / 8;
487 case RTDIGESTTYPE_SHA512: return 512 / 8;
488 case RTDIGESTTYPE_SHA512T224: return 224 / 8;
489 case RTDIGESTTYPE_SHA512T256: return 256 / 8;
490 case RTDIGESTTYPE_SHA3_224: return 224 / 8;
491 case RTDIGESTTYPE_SHA3_256: return 256 / 8;
492 case RTDIGESTTYPE_SHA3_384: return 384 / 8;
493 case RTDIGESTTYPE_SHA3_512: return 512 / 8;
494 default:
495 AssertFailed();
496 return 0;
497 }
498}
499
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