VirtualBox

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