VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/pkix-signature-core.cpp

Last change on this file was 100442, checked in by vboxsync, 11 months ago

IPRT,OpenSSL: Support ECDSA for verficiation purposes when IPRT links with OpenSSL. This required quite a bit of cleanups, so not entirely no-risk. bugref:10479 ticketref:21621

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1/* $Id: pkix-signature-core.cpp 100442 2023-07-08 11:10:51Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - Public Key Signature Schema Algorithm, Core API.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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/pkix.h>
43
44#include <iprt/assert.h>
45#include <iprt/asm.h>
46#include <iprt/errcore.h>
47#include <iprt/mem.h>
48#include <iprt/string.h>
49#include <iprt/crypto/digest.h>
50#include <iprt/crypto/key.h>
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/**
57 * Generic public key signature scheme instance.
58 */
59typedef struct RTCRPKIXSIGNATUREINT
60{
61 /** Magic value (RTCRPKIXSIGNATUREINT_MAGIC). */
62 uint32_t u32Magic;
63 /** Reference counter. */
64 uint32_t volatile cRefs;
65 /** Pointer to the message digest descriptor. */
66 PCRTCRPKIXSIGNATUREDESC pDesc;
67 /** Key being used (referrenced of course). */
68 RTCRKEY hKey;
69 /** The operation this instance is licensed for. */
70 bool fSigning;
71 /** State. */
72 uint32_t uState;
73
74 /** Opaque data specific to the message digest algorithm, size given by
75 * RTCRPKIXSIGNATUREDESC::cbState. */
76 uint8_t abState[1];
77} RTCRPKIXSIGNATUREINT;
78AssertCompileMemberAlignment(RTCRPKIXSIGNATUREINT, abState, 8);
79/** Pointer to a public key algorithm instance. */
80typedef RTCRPKIXSIGNATUREINT *PRTCRPKIXSIGNATUREINT;
81
82/** Magic value for RTCRPKIXSIGNATUREINT::u32Magic (Baley Withfield Diffie). */
83#define RTCRPKIXSIGNATUREINT_MAGIC UINT32_C(0x19440605)
84
85/** @name RTCRPKIXSIGNATUREINT::uState values.
86 * @{ */
87/** Ready to go. */
88#define RTCRPKIXSIGNATURE_STATE_READY UINT32_C(1)
89/** Need reset. */
90#define RTCRPKIXSIGNATURE_STATE_DONE UINT32_C(2)
91/** Busted state, can happen after re-init. */
92#define RTCRPKIXSIGNATURE_STATE_BUSTED UINT32_C(3)
93/** @} */
94
95
96
97RTDECL(int) RTCrPkixSignatureCreate(PRTCRPKIXSIGNATURE phSignature, PCRTCRPKIXSIGNATUREDESC pDesc, void *pvOpaque,
98 bool fSigning, RTCRKEY hKey, PCRTASN1DYNTYPE pParams)
99{
100 /*
101 * Validate input.
102 */
103 AssertPtrReturn(phSignature, VERR_INVALID_POINTER);
104 AssertPtrReturn(pDesc, VERR_INVALID_POINTER);
105 uint32_t cKeyRefs = RTCrKeyRetain(hKey);
106 AssertReturn(cKeyRefs != UINT32_MAX, VERR_INVALID_HANDLE);
107
108 /*
109 * Instantiate the algorithm for the given operation.
110 */
111 int rc = VINF_SUCCESS;
112 PRTCRPKIXSIGNATUREINT pThis = (PRTCRPKIXSIGNATUREINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTCRPKIXSIGNATUREINT,
113 abState[pDesc->cbState]));
114 if (pThis)
115 {
116 pThis->u32Magic = RTCRPKIXSIGNATUREINT_MAGIC;
117 pThis->cRefs = 1;
118 pThis->pDesc = pDesc;
119 pThis->fSigning = fSigning;
120 pThis->uState = RTCRPKIXSIGNATURE_STATE_READY;
121 pThis->hKey = hKey;
122 if (pDesc->pfnInit)
123 rc = pDesc->pfnInit(pDesc, pThis->abState, pvOpaque, fSigning, hKey, pParams);
124 else
125 rc = RTCrKeyVerifyParameterCompatibility(hKey, pParams, true /*fForSignature*/,
126 NULL /*pAlgorithm*/, NULL /*pErrInfo*/);
127 if (RT_SUCCESS(rc))
128 {
129 *phSignature = pThis;
130 return VINF_SUCCESS;
131 }
132 pThis->u32Magic = 0;
133 RTMemFree(pThis);
134 }
135 else
136 rc = VERR_NO_MEMORY;
137 RTCrKeyRelease(hKey);
138 return rc;
139
140}
141
142
143RTDECL(uint32_t) RTCrPkixSignatureRetain(RTCRPKIXSIGNATURE hSignature)
144{
145 PRTCRPKIXSIGNATUREINT pThis = hSignature;
146 AssertPtrReturn(pThis, UINT32_MAX);
147 AssertReturn(pThis->u32Magic == RTCRPKIXSIGNATUREINT_MAGIC, UINT32_MAX);
148
149 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
150 Assert(cRefs < 64);
151 return cRefs;
152}
153
154
155/**
156 * Destructor worker.
157 */
158static uint32_t rtCrPkixSignatureDestructor(PRTCRPKIXSIGNATUREINT pThis)
159{
160 pThis->u32Magic = ~RTCRPKIXSIGNATUREINT_MAGIC;
161 if (pThis->pDesc->pfnDelete)
162 pThis->pDesc->pfnDelete(pThis->pDesc, pThis->abState, pThis->fSigning);
163
164 RTCrKeyRelease(pThis->hKey);
165 pThis->hKey = NIL_RTCRKEY;
166
167 size_t cbToWipe = RT_UOFFSETOF_DYN(RTCRPKIXSIGNATUREINT, abState[pThis->pDesc->cbState]);
168 RTMemWipeThoroughly(pThis, cbToWipe, 6);
169
170 RTMemFree(pThis);
171 return 0;
172}
173
174
175RTDECL(uint32_t) RTCrPkixSignatureRelease(RTCRPKIXSIGNATURE hSignature)
176{
177 PRTCRPKIXSIGNATUREINT pThis = hSignature;
178 if (pThis == NIL_RTCRPKIXSIGNATURE)
179 return 0;
180 AssertPtrReturn(pThis, UINT32_MAX);
181 AssertReturn(pThis->u32Magic == RTCRPKIXSIGNATUREINT_MAGIC, UINT32_MAX);
182
183 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
184 Assert(cRefs < 64);
185 if (!cRefs)
186 return rtCrPkixSignatureDestructor(pThis);
187 return cRefs;
188}
189
190
191/**
192 * Resets the signature provider instance prior to a new signing or verification
193 * opartion.
194 *
195 * @returns IPRT status code.
196 * @param pThis The instance to reset.
197 */
198static int rtCrPkxiSignatureReset(PRTCRPKIXSIGNATUREINT pThis)
199{
200 if (pThis->uState == RTCRPKIXSIGNATURE_STATE_DONE)
201 {
202 if (pThis->pDesc->pfnReset)
203 {
204 int rc = pThis->pDesc->pfnReset(pThis->pDesc, pThis->abState, pThis->fSigning);
205 if (RT_FAILURE(rc))
206 {
207 pThis->uState = RTCRPKIXSIGNATURE_STATE_BUSTED;
208 return rc;
209 }
210 }
211 pThis->uState = RTCRPKIXSIGNATURE_STATE_READY;
212 }
213 return VINF_SUCCESS;
214}
215
216
217RTDECL(int) RTCrPkixSignatureVerify(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest,
218 void const *pvSignature, size_t cbSignature)
219{
220 PRTCRPKIXSIGNATUREINT pThis = hSignature;
221 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
222 AssertReturn(pThis->u32Magic == RTCRPKIXSIGNATUREINT_MAGIC, VERR_INVALID_HANDLE);
223 AssertReturn(!pThis->fSigning, VERR_INVALID_FUNCTION);
224 AssertReturn(pThis->uState == RTCRPKIXSIGNATURE_STATE_READY || pThis->uState == RTCRPKIXSIGNATURE_STATE_DONE, VERR_INVALID_STATE);
225
226 uint32_t cRefs = RTCrDigestRetain(hDigest);
227 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
228
229 int rc = rtCrPkxiSignatureReset(pThis);
230 if (RT_SUCCESS(rc))
231 {
232 rc = pThis->pDesc->pfnVerify(pThis->pDesc, pThis->abState, pThis->hKey, hDigest, pvSignature, cbSignature);
233 pThis->uState = RTCRPKIXSIGNATURE_STATE_DONE;
234 }
235
236 RTCrDigestRelease(hDigest);
237 return rc;
238}
239
240
241RTDECL(int) RTCrPkixSignatureVerifyBitString(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, PCRTASN1BITSTRING pSignature)
242{
243 /*
244 * Just unpack it and pass it on to the lower level API.
245 */
246 AssertPtrReturn(pSignature, VERR_INVALID_POINTER);
247 AssertReturn(RTAsn1BitString_IsPresent(pSignature), VERR_INVALID_PARAMETER);
248 uint32_t cbData = RTASN1BITSTRING_GET_BYTE_SIZE(pSignature);
249 void const *pvData = RTASN1BITSTRING_GET_BIT0_PTR(pSignature);
250 AssertPtrReturn(pvData, VERR_INVALID_PARAMETER);
251
252 return RTCrPkixSignatureVerify(hSignature, hDigest, pvData, cbData);
253}
254
255
256RTDECL(int) RTCrPkixSignatureVerifyOctetString(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest, PCRTASN1OCTETSTRING pSignature)
257{
258 /*
259 * Just unpack it and pass it on to the lower level API.
260 */
261 AssertPtrReturn(pSignature, VERR_INVALID_POINTER);
262 AssertReturn(RTAsn1OctetString_IsPresent(pSignature), VERR_INVALID_PARAMETER);
263 uint32_t cbData = pSignature->Asn1Core.cb;
264 void const *pvData = pSignature->Asn1Core.uData.pv;
265 AssertPtrReturn(pvData, VERR_INVALID_PARAMETER);
266
267 return RTCrPkixSignatureVerify(hSignature, hDigest, pvData, cbData);
268}
269
270
271RTDECL(int) RTCrPkixSignatureSign(RTCRPKIXSIGNATURE hSignature, RTCRDIGEST hDigest,
272 void *pvSignature, size_t *pcbSignature)
273{
274 PRTCRPKIXSIGNATUREINT pThis = hSignature;
275 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
276 AssertReturn(pThis->u32Magic == RTCRPKIXSIGNATUREINT_MAGIC, VERR_INVALID_HANDLE);
277 AssertReturn(pThis->fSigning, VERR_INVALID_FUNCTION);
278 AssertReturn(pThis->uState == RTCRPKIXSIGNATURE_STATE_READY || pThis->uState == RTCRPKIXSIGNATURE_STATE_DONE, VERR_INVALID_STATE);
279
280 uint32_t cRefs = RTCrDigestRetain(hDigest);
281 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
282
283 int rc = rtCrPkxiSignatureReset(pThis);
284 if (RT_SUCCESS(rc))
285 {
286 rc = pThis->pDesc->pfnSign(pThis->pDesc, pThis->abState, pThis->hKey, hDigest, pvSignature, pcbSignature);
287 if (rc != VERR_BUFFER_OVERFLOW)
288 pThis->uState = RTCRPKIXSIGNATURE_STATE_DONE;
289 }
290
291 RTCrDigestRelease(hDigest);
292 return rc;
293}
294
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use