VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/pkcs7-sign.cpp

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.7 KB
Line 
1/* $Id: pkcs7-sign.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - PKCS \#7, Signing
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/pkcs7.h>
43
44#include <iprt/err.h>
45#include <iprt/string.h>
46#include <iprt/crypto/digest.h>
47#include <iprt/crypto/key.h>
48#include <iprt/crypto/pkix.h>
49#include <iprt/crypto/store.h>
50#include <iprt/crypto/x509.h>
51
52#ifdef IPRT_WITH_OPENSSL
53# include "internal/iprt-openssl.h"
54# include "internal/openssl-pre.h"
55# include <openssl/asn1t.h>
56# include <openssl/pkcs7.h>
57# include <openssl/cms.h>
58# include <openssl/x509.h>
59# include <openssl/err.h>
60# include "internal/openssl-post.h"
61#endif
62
63
64/*********************************************************************************************************************************
65* Structures and Typedefs *
66*********************************************************************************************************************************/
67/**
68 * PKCS\#7 / CMS signing operation instance.
69 */
70typedef struct RTCRPKCS7SIGNINGJOBINT
71{
72 /** Magic value (RTCRPKCS7SIGNINGJOBINT). */
73 uint32_t u32Magic;
74 /** Reference counter. */
75 uint32_t volatile cRefs;
76 /** RTCRPKCS7SIGN_F_XXX. */
77 uint64_t fFlags;
78 /** Set if finalized. */
79 bool fFinallized;
80
81 //....
82} RTCRPKCS7SIGNINGJOBINT;
83
84/** Magic value for RTCRPKCS7SIGNINGJOBINT (Jonathan Lethem). */
85#define RTCRPKCS7SIGNINGJOBINT_MAGIC UINT32_C(0x19640219)
86
87/** Handle to PKCS\#7/CMS signing operation. */
88typedef struct RTCRPKCS7SIGNINGJOBINT *RTCRPKCS7SIGNINGJOB;
89/** Pointer to a PKCS\#7/CMS signing operation handle. */
90typedef RTCRPKCS7SIGNINGJOB *PRTCRPKCS7SIGNINGJOB;
91
92//// CMS_sign
93//RTDECL(int) RTCrPkcs7Sign(PRTCRPKCS7SIGNINGJOB *phJob, uint64_t fFlags, PCRTCRX509CERTIFICATE pSigner, RTCRKEY hPrivateKey,
94// RTCRSTORE hAdditionalCerts,
95//
96
97#ifdef IPRT_WITH_OPENSSL
98
99static int rtCrPkcs7SimpleSignSignedDataDoV1TweakContent(PKCS7 *pOsslPkcs7, const char *pszContentId,
100 const void *pvData, size_t cbData,
101 PRTERRINFO pErrInfo)
102{
103 AssertReturn(pszContentId, RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB,
104 "RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP requires content type in additional attribs"));
105
106 /*
107 * Create a new inner PKCS#7 content container, forcing it to the 'other' type.
108 */
109 PKCS7 *pOsslInnerContent = PKCS7_new();
110 if (!pOsslInnerContent)
111 return RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "PKCS7_new failed");
112
113 /* Set the type. */
114 int rc;
115 pOsslInnerContent->type = OBJ_txt2obj(pszContentId, 1);
116 if (pOsslInnerContent->type)
117 {
118 /* Create a dynamic ASN1 type which we set to a sequence. */
119 ASN1_TYPE *pOsslOther = pOsslInnerContent->d.other = ASN1_TYPE_new();
120 if (pOsslOther)
121 {
122 pOsslOther->type = V_ASN1_SEQUENCE;
123
124 /* Create a string and put the data in it. */
125 ASN1_STRING *pOsslStr = pOsslOther->value.sequence = ASN1_STRING_new();
126 if (pOsslStr)
127 {
128 rc = ASN1_STRING_set(pOsslStr, pvData, (int)cbData); /* copies the buffer content */
129 if (rc > 0)
130 {
131 /*
132 * Set the content in the PKCS#7 signed data we're constructing.
133 * This consumes pOsslInnerContent on success.
134 */
135 rc = PKCS7_set_content(pOsslPkcs7, pOsslInnerContent);
136 if (rc > 0)
137 return VINF_SUCCESS;
138
139 /* failed */
140 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "PKCS7_set_content");
141 }
142 else
143 rc = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "ASN1_STRING_set(,,%#x)", cbData);
144 }
145 else
146 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "ASN1_STRING_new");
147 }
148 else
149 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "ASN1_TYPE_new");
150 }
151 else
152 rc = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "OBJ_txt2obj(%s, 1) failed", pszContentId);
153 PKCS7_free(pOsslInnerContent);
154 return rc;
155}
156
157
158static int rtCrPkcs7SimpleSignSignedDataDoV1TweakedFinal(PKCS7 *pOsslPkcs7, const char *pszContentId,
159 const void *pvData, size_t cbData, PRTERRINFO pErrInfo)
160{
161 AssertReturn(pszContentId, RTErrInfoSet(pErrInfo, VERR_CR_PKCS7_MISSING_CONTENT_TYPE_ATTRIB,
162 "RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP requires content type in additional attribs"));
163
164 /*
165 * Prepare a BIO of what should be hashed with all the hashing filters attached.
166 */
167 BIO *pOsslBio = PKCS7_dataInit(pOsslPkcs7, NULL);
168 if (!pOsslBio)
169 return RTErrInfoSet(pErrInfo, VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED, "PKCS7_dataInit failed");
170
171 /*
172 * Now write the data.
173 *
174 * We must skip the outer wrapper here (see RTCrPkcs7VerifySignedData). This
175 * is probably a bit presumptive about what we're working on, so add an extra
176 * flag for this later.
177 */
178 uint8_t const *pbToWrite = (uint8_t const *)pvData;
179 size_t cbToWrite = cbData;
180
181 /** @todo add extra flag for this? */
182 RTASN1CURSORPRIMARY SkipCursor;
183 RTAsn1CursorInitPrimary(&SkipCursor, pvData, (uint32_t)cbData,
184 pErrInfo,&g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "skip");
185 RTASN1CORE SkipAsn1Core = { 0 };
186 int rc = RTAsn1CursorReadHdr(&SkipCursor.Cursor, &SkipAsn1Core, "skip-core");
187 if (RT_SUCCESS(rc))
188 {
189 pbToWrite += SkipAsn1Core.cbHdr;
190 cbToWrite -= SkipAsn1Core.cbHdr;
191
192 rc = BIO_write(pOsslBio, pbToWrite, (int)cbToWrite);
193 if (rc == (ssize_t)cbToWrite)
194 {
195 BIO_flush(pOsslBio); /** @todo error check this */
196 if (true)
197 {
198 /*
199 * Finalize the job - produce the signer info signatures and stuff.
200 */
201 rc = PKCS7_dataFinal(pOsslPkcs7, pOsslBio);
202 if (rc > 0)
203 {
204 /*
205 * Now tweak the content so we get the desired content type and
206 * no extra wrappers and stuff.
207 */
208 rc = rtCrPkcs7SimpleSignSignedDataDoV1TweakContent(pOsslPkcs7, pszContentId, pvData, cbData, pErrInfo);
209 }
210 else
211 rc = RTErrInfoSetF(pErrInfo, VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED, "PKCS7_dataFinal failed: %d", rc);
212 }
213 }
214 else
215 rc = RTErrInfoSetF(pErrInfo, VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED,
216 "%zu byte data write failed: %d", cbToWrite, rc);
217 }
218 BIO_free_all(pOsslBio);
219 return rc;
220}
221
222
223static int rtCrPkcs7SimpleSignSignedDataDoV1AttribConversion(PKCS7_SIGNER_INFO *pSignerInfo,
224 PCRTCRPKCS7ATTRIBUTES pAdditionalAuthenticatedAttribs,
225 const char **ppszContentId, PRTERRINFO pErrInfo)
226{
227 int rc = VINF_SUCCESS;
228 *ppszContentId = NULL;
229
230 if (pAdditionalAuthenticatedAttribs)
231 {
232
233 /*
234 * Convert each attribute.
235 */
236 STACK_OF(X509_ATTRIBUTE) *pOsslAttributes = sk_X509_ATTRIBUTE_new_null();
237 for (uint32_t i = 0; i < pAdditionalAuthenticatedAttribs->cItems && RT_SUCCESS(rc); i++)
238 {
239 PCRTCRPKCS7ATTRIBUTE pAttrib = pAdditionalAuthenticatedAttribs->papItems[i];
240
241 /* Look out for content type, as we will probably need that for
242 RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP later. */
243 if ( pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS
244 && RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_CONTENT_TYPE_OID) == 0)
245 {
246 AssertBreakStmt(!*ppszContentId, rc = VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB);
247 AssertBreakStmt(pAttrib->uValues.pObjIds && pAttrib->uValues.pObjIds->cItems == 1,
248 rc = VERR_CR_PKCS7_BAD_CONTENT_TYPE_ATTRIB);
249 *ppszContentId = pAttrib->uValues.pObjIds->papItems[0]->szObjId;
250 }
251
252 /* The conversion (IPRT encode, OpenSSL decode). */
253 X509_ATTRIBUTE *pOsslAttrib;
254 rc = rtCrOpenSslConvertPkcs7Attribute((void **)&pOsslAttrib, pAttrib, pErrInfo);
255 if (RT_SUCCESS(rc))
256 {
257 if (!sk_X509_ATTRIBUTE_push(pOsslAttributes, pOsslAttrib))
258 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "sk_X509_ATTRIBUTE_push failed");
259 }
260 }
261
262 /*
263 * If we've successfully converted all the attributes, make a deep copy
264 * (waste of resource, but whatever) into the signer info we're working on.
265 */
266 if (RT_SUCCESS(rc))
267 {
268 rc = PKCS7_set_signed_attributes(pSignerInfo, pOsslAttributes); /* deep copy */
269 if (rc <= 0)
270 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "PKCS7_set_signed_attributes failed");
271 }
272
273 /*
274 * Free the attributes (they were copied). Cannot use X509_ATTRIBUTE_pop_free as
275 * the callback causes Visual C++ to complain about exceptions on the callback.
276 */
277 for (int i = sk_X509_ATTRIBUTE_num(pOsslAttributes) - 1; i >= 0; i--)
278 X509_ATTRIBUTE_free(sk_X509_ATTRIBUTE_value(pOsslAttributes, i));
279 sk_X509_ATTRIBUTE_free(pOsslAttributes);
280 }
281 return rc;
282}
283
284static int rtCrPkcs7SimpleSignSignedDataDoV1(uint32_t fFlags, X509 *pOsslSigner, EVP_PKEY *pEvpPrivateKey,
285 BIO *pOsslData, const EVP_MD *pEvpMd, STACK_OF(X509) *pOsslAdditionalCerts,
286 PCRTCRPKCS7ATTRIBUTES pAdditionalAuthenticatedAttribs,
287 const void *pvData, size_t cbData,
288 BIO **ppOsslResult, PRTERRINFO pErrInfo)
289{
290 /*
291 * Use PKCS7_sign with PKCS7_PARTIAL to start a extended the signing process.
292 */
293 /* Create a ContentInfo we can modify using CMS_sign w/ CMS_PARTIAL. */
294 unsigned int fOsslSign = PKCS7_BINARY | PKCS7_PARTIAL;
295 if (fFlags & RTCRPKCS7SIGN_SD_F_DEATCHED)
296 fOsslSign |= PKCS7_DETACHED;
297 if (fFlags & RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP)
298 fOsslSign |= PKCS7_NOSMIMECAP;
299 int rc = VINF_SUCCESS;
300 PKCS7 *pCms = PKCS7_sign(NULL, NULL, pOsslAdditionalCerts, NULL, fOsslSign);
301 if (pCms != NULL)
302 {
303 /*
304 * Add a signer.
305 */
306 PKCS7_SIGNER_INFO *pSignerInfo = PKCS7_sign_add_signer(pCms, pOsslSigner, pEvpPrivateKey, pEvpMd, fOsslSign);
307 if (pSignerInfo)
308 {
309 /*
310 * Add additional attributes to the signer.
311 */
312 const char *pszContentId = NULL;
313 rc = rtCrPkcs7SimpleSignSignedDataDoV1AttribConversion(pSignerInfo, pAdditionalAuthenticatedAttribs,
314 &pszContentId, pErrInfo);
315 if (RT_SUCCESS(rc))
316 {
317 /*
318 * Finalized and actually sign the data.
319 */
320 bool const fTweaked = (fFlags & (RTCRPKCS7SIGN_SD_F_DEATCHED | RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP))
321 == RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP;
322 if (fTweaked)
323 rc = rtCrPkcs7SimpleSignSignedDataDoV1TweakedFinal(pCms, pszContentId, pvData, cbData, pErrInfo);
324 else
325 {
326 rc = PKCS7_final(pCms, pOsslData, fOsslSign);
327 if (rc > 0)
328 rc = VINF_SUCCESS;
329 else
330 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "PKCS7_final");
331 /** @todo maybe we want to use rtCrPkcs7SimpleSignSignedDataDoV1TweakContent
332 * for when the content type isn't 'data'... */
333 }
334 if (RT_SUCCESS(rc))
335 {
336 /*
337 * Get the output and copy it into the result buffer.
338 */
339 BIO *pOsslResult = BIO_new(BIO_s_mem());
340 if (pOsslResult)
341 {
342 rc = i2d_PKCS7_bio(pOsslResult, pCms);
343 if (rc > 0)
344 {
345 *ppOsslResult = pOsslResult;
346 rc = VINF_SUCCESS;
347 }
348 else
349 {
350 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "i2d_PKCS7_bio");
351 BIO_free(pOsslResult);
352 }
353 }
354 else
355 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "BIO_new/BIO_s_mem");
356 }
357 }
358 else
359 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "PKCS7_sign_add_signer");
360 }
361 PKCS7_free(pCms);
362 }
363 else
364 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "PKCS7_sign");
365 return rc;
366}
367
368
369static int rtCrPkcs7SimpleSignSignedDataDoDefault(uint32_t fFlags, X509 *pOsslSigner, EVP_PKEY *pEvpPrivateKey,
370 BIO *pOsslData, const EVP_MD *pEvpMd, STACK_OF(X509) *pOsslAdditionalCerts,
371 PCRTCRPKCS7ATTRIBUTES pAdditionalAuthenticatedAttribs,
372 BIO **ppOsslResult, PRTERRINFO pErrInfo)
373
374{
375 /*
376 * Use CMS_sign with CMS_PARTIAL to start a extended the signing process.
377 */
378 /* Create a ContentInfo we can modify using CMS_sign w/ CMS_PARTIAL. */
379 unsigned int fOsslSign = CMS_BINARY | CMS_PARTIAL;
380 if (fFlags & RTCRPKCS7SIGN_SD_F_DEATCHED)
381 fOsslSign |= CMS_DETACHED;
382 if (fFlags & RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP)
383 fOsslSign |= CMS_NOSMIMECAP;
384 int rc = VINF_SUCCESS;
385 CMS_ContentInfo *pCms = CMS_sign(NULL, NULL, pOsslAdditionalCerts, NULL, fOsslSign);
386 if (pCms != NULL)
387 {
388 /*
389 * Set encapsulated content type if present in the auth attribs.
390 */
391 uint32_t iAuthAttrSkip = UINT32_MAX;
392 for (uint32_t i = 0; i < pAdditionalAuthenticatedAttribs->cItems && RT_SUCCESS(rc); i++)
393 {
394 PCRTCRPKCS7ATTRIBUTE pAttrib = pAdditionalAuthenticatedAttribs->papItems[i];
395 if ( pAttrib->enmType == RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS
396 && RTAsn1ObjId_CompareWithString(&pAttrib->Type, RTCR_PKCS9_ID_CONTENT_TYPE_OID) == 0)
397 {
398 AssertBreakStmt(pAttrib->uValues.pObjIds && pAttrib->uValues.pObjIds->cItems == 1,
399 rc = VERR_INTERNAL_ERROR_3);
400 PCRTASN1OBJID pObjId = pAttrib->uValues.pObjIds->papItems[0];
401 ASN1_OBJECT *pOsslObjId = OBJ_txt2obj(pObjId->szObjId, 0 /*no_name*/);
402 if (pOsslObjId)
403 {
404 rc = CMS_set1_eContentType(pCms, pOsslObjId);
405 ASN1_OBJECT_free(pOsslObjId);
406 if (rc < 0)
407 rc = RTErrInfoSetF(pErrInfo, VERR_CR_PKIX_GENERIC_ERROR,
408 "CMS_set1_eContentType(%s)", pObjId->szObjId);
409 }
410 else
411 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "OBJ_txt2obj");
412
413 iAuthAttrSkip = i;
414 break;
415 }
416 }
417 if (RT_SUCCESS(rc))
418 {
419 /*
420 * Add a signer.
421 */
422 CMS_SignerInfo *pSignerInfo = CMS_add1_signer(pCms, pOsslSigner, pEvpPrivateKey, pEvpMd, fOsslSign);
423 if (pSignerInfo)
424 {
425 /*
426 * Add additional attributes, skipping the content type if found above.
427 */
428 if (pAdditionalAuthenticatedAttribs)
429 for (uint32_t i = 0; i < pAdditionalAuthenticatedAttribs->cItems && RT_SUCCESS(rc); i++)
430 if (i != iAuthAttrSkip)
431 {
432 PCRTCRPKCS7ATTRIBUTE pAttrib = pAdditionalAuthenticatedAttribs->papItems[i];
433 X509_ATTRIBUTE *pOsslAttrib;
434 rc = rtCrOpenSslConvertPkcs7Attribute((void **)&pOsslAttrib, pAttrib, pErrInfo);
435 if (RT_SUCCESS(rc))
436 {
437 rc = CMS_signed_add1_attr(pSignerInfo, pOsslAttrib);
438 rtCrOpenSslFreeConvertedPkcs7Attribute((void **)pOsslAttrib);
439 if (rc <= 0)
440 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "CMS_signed_add1_attr");
441 }
442 }
443 if (RT_SUCCESS(rc))
444 {
445 /*
446 * Finalized and actually sign the data.
447 */
448 rc = CMS_final(pCms, pOsslData, NULL /*dcont*/, fOsslSign);
449 if (rc > 0)
450 {
451 /*
452 * Get the output and copy it into the result buffer.
453 */
454 BIO *pOsslResult = BIO_new(BIO_s_mem());
455 if (pOsslResult)
456 {
457 rc = i2d_CMS_bio(pOsslResult, pCms);
458 if (rc > 0)
459 {
460 *ppOsslResult = pOsslResult;
461 rc = VINF_SUCCESS;
462 }
463 else
464 {
465 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "i2d_CMS_bio");
466 BIO_free(pOsslResult);
467 }
468 }
469 else
470 rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "BIO_new/BIO_s_mem");
471 }
472 else
473 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "CMS_final");
474 }
475 }
476 else
477 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "CMS_add1_signer");
478 }
479 CMS_ContentInfo_free(pCms);
480 }
481 else
482 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "CMS_sign");
483 return rc;
484}
485
486#endif /* IPRT_WITH_OPENSSL */
487
488
489
490RTDECL(int) RTCrPkcs7SimpleSignSignedData(uint32_t fFlags, PCRTCRX509CERTIFICATE pSigner, RTCRKEY hPrivateKey,
491 void const *pvData, size_t cbData, RTDIGESTTYPE enmDigestType,
492 RTCRSTORE hAdditionalCerts, PCRTCRPKCS7ATTRIBUTES pAdditionalAuthenticatedAttribs,
493 void *pvResult, size_t *pcbResult, PRTERRINFO pErrInfo)
494{
495 size_t const cbResultBuf = *pcbResult;
496 *pcbResult = 0;
497 AssertReturn(!(fFlags & ~RTCRPKCS7SIGN_SD_F_VALID_MASK), VERR_INVALID_FLAGS);
498#ifdef IPRT_WITH_OPENSSL
499 AssertReturn((int)cbData >= 0 && (unsigned)cbData == cbData, VERR_TOO_MUCH_DATA);
500
501 /*
502 * Resolve the digest type.
503 */
504 const EVP_MD *pEvpMd = NULL;
505 if (enmDigestType != RTDIGESTTYPE_UNKNOWN)
506 {
507 pEvpMd = (const EVP_MD *)rtCrOpenSslConvertDigestType(enmDigestType, pErrInfo);
508 AssertReturn(pEvpMd, pErrInfo ? pErrInfo->rc : VERR_INVALID_PARAMETER);
509 }
510
511 /*
512 * Convert the private key.
513 */
514 EVP_PKEY *pEvpPrivateKey = NULL;
515 int rc = rtCrKeyToOpenSslKey(hPrivateKey, false /*fNeedPublic*/, (void **)&pEvpPrivateKey, pErrInfo);
516 if (RT_SUCCESS(rc))
517 {
518 /*
519 * Convert the signing certificate.
520 */
521 X509 *pOsslSigner = NULL;
522 rc = rtCrOpenSslConvertX509Cert((void **)&pOsslSigner, pSigner, pErrInfo);
523 if (RT_SUCCESS(rc))
524 {
525 /*
526 * Convert any additional certificates.
527 */
528 STACK_OF(X509) *pOsslAdditionalCerts = NULL;
529 if (hAdditionalCerts != NIL_RTCRSTORE)
530 rc = RTCrStoreConvertToOpenSslCertStack(hAdditionalCerts, 0 /*fFlags*/, (void **)&pOsslAdditionalCerts, pErrInfo);
531 if (RT_SUCCESS(rc))
532 {
533 /*
534 * Create a BIO for the data buffer.
535 */
536 BIO *pOsslData = BIO_new_mem_buf((void *)pvData, (int)cbData);
537 if (pOsslData)
538 {
539 /*
540 * Do the work.
541 */
542 BIO *pOsslResult = NULL;
543 if (!(fFlags & RTCRPKCS7SIGN_SD_F_USE_V1))
544 rc = rtCrPkcs7SimpleSignSignedDataDoDefault(fFlags, pOsslSigner, pEvpPrivateKey, pOsslData, pEvpMd,
545 pOsslAdditionalCerts, pAdditionalAuthenticatedAttribs,
546 &pOsslResult, pErrInfo);
547 else
548 rc = rtCrPkcs7SimpleSignSignedDataDoV1(fFlags, pOsslSigner, pEvpPrivateKey, pOsslData, pEvpMd,
549 pOsslAdditionalCerts, pAdditionalAuthenticatedAttribs,
550 pvData, cbData,
551 &pOsslResult, pErrInfo);
552 BIO_free(pOsslData);
553 if (RT_SUCCESS(rc))
554 {
555 /*
556 * Copy out the result.
557 */
558 BUF_MEM *pBuf = NULL;
559 rc = (int)BIO_get_mem_ptr(pOsslResult, &pBuf);
560 if (rc > 0)
561 {
562 AssertPtr(pBuf);
563 size_t const cbResult = pBuf->length;
564 if ( cbResultBuf >= cbResult
565 && pvResult != NULL)
566 {
567 memcpy(pvResult, pBuf->data, cbResult);
568 rc = VINF_SUCCESS;
569 }
570 else
571 rc = VERR_BUFFER_OVERFLOW;
572 *pcbResult = cbResult;
573 }
574 else
575 rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "BIO_get_mem_ptr");
576 BIO_free(pOsslResult);
577 }
578 }
579 }
580 rtCrOpenSslFreeConvertedX509Cert(pOsslSigner);
581 }
582 EVP_PKEY_free(pEvpPrivateKey);
583 }
584 return rc;
585#else
586 RT_NOREF(fFlags, pSigner, hPrivateKey, pvData, cbData, enmDigestType, hAdditionalCerts, pAdditionalAuthenticatedAttribs,
587 pvResult, pErrInfo, cbResultBuf);
588 *pcbResult = 0;
589 return VERR_NOT_IMPLEMENTED;
590#endif
591}
592
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use