scep_client_req_format.c
Go to the documentation of this file.
1 /**
2  * @file scep_client_req_format.c
3  * @brief SCEP request generation
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SCEP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "scep/scep_client.h"
37 #include "scep/scep_client_misc.h"
38 #include "pkcs7/pkcs7_format.h"
39 #include "pkcs7/pkcs7_encrypt.h"
41 #include "pkix/x509_cert_parse.h"
42 #include "pkix/x509_cert_format.h"
43 #include "pkix/x509_csr_parse.h"
44 #include "encoding/asn1.h"
45 #include "debug.h"
46 
47 //Check crypto library configuration
48 #if (SCEP_CLIENT_SUPPORT == ENABLED)
49 
50 
51 /**
52  * @brief Format PKI message
53  * @param[in] context Pointer to the SCEP client context
54  * @param[in] messageType SCEP message type
55  * @param[out] output Buffer where to format the PKI message
56  * @param[out] written Length of the resulting PKI message
57  * @return Error code
58  **/
59 
61  ScepMessageType messageType, uint8_t *output, size_t *written)
62 {
63  error_t error;
64  size_t n;
65  time_t currentTime;
66  X509CertInfo *certInfo;
67  Pkcs7ContentInfo contentInfo;
69  X509SignAlgoId signatureAlgo;
70  char_t buffer[3];
71 
72  //The messageType attribute specifies the type of operation performed by the
73  //transaction. This attribute must be included in all PKI messages (refer to
74  //RFC 8894, section 3.2.1.2)
75  osSprintf(buffer, "%u", (uint_t) messageType);
76 
77  //When a sender sends a PKI message to a recipient, a fresh senderNonce
78  //must be included in the message (refer to RFC 8894, section 3.2.1.5)
79  error = context->prngAlgo->read(context->prngContext, context->senderNonce,
81  //Any error to report?
82  if(error)
83  return error;
84 
85  //The signed content must be a pkcsPKIEnvelope
86  error = scepClientFormatPkcsPkiEnvelope(context, messageType, output, &n);
87  //Any error to report?
88  if(error)
89  return error;
90 
91  //Clear authenticatedAttributes structure
93 
94  //The authenticatedAttributes field must contain a PKCS #9 content-type
95  //attribute having as its value the content type of the ContentInfo value
96  //being signed (refer to RFC 2315, section 9.2)
97  attributes.contentType.value = PKCS7_DATA_OID;
98  attributes.contentType.length = sizeof(PKCS7_DATA_OID);
99 
100  //Retrieve current time
101  currentTime = getCurrentUnixTime();
102 
103  //Any real-time clock implemented?
104  if(currentTime != 0)
105  {
106  //Other attribute types that might be useful here, such as signing time,
107  //can be included
108  convertUnixTimeToDate(currentTime, &attributes.signingTime);
109  }
110 
111  //At a minimum, all messages must contain a transactionID attribute, a
112  //messageType attribute and a fresh senderNonce attribute (refer to RFC 8894,
113  //section 3.2.1)
114  attributes.numCustomAttributes = 3;
115 
116  //Format transactionID attribute
117  attributes.customAttributes[0].oid.value = SCEP_TRANSACTION_ID_OID;
118  attributes.customAttributes[0].oid.length = sizeof(SCEP_TRANSACTION_ID_OID);
119  attributes.customAttributes[0].type = ASN1_TYPE_PRINTABLE_STRING;
120  attributes.customAttributes[0].data.value = (uint8_t *) context->transactionId;
121  attributes.customAttributes[0].data.length = osStrlen(context->transactionId);
122 
123  //Format messageType attribute
124  attributes.customAttributes[1].oid.value = SCEP_MESSAGE_TYPE_OID;
125  attributes.customAttributes[1].oid.length = sizeof(SCEP_MESSAGE_TYPE_OID);
126  attributes.customAttributes[1].type = ASN1_TYPE_PRINTABLE_STRING;
127  attributes.customAttributes[1].data.value = (uint8_t *) buffer;
128  attributes.customAttributes[1].data.length = osStrlen(buffer);
129 
130  //Format senderNonce attribute
131  attributes.customAttributes[2].oid.value = SCEP_SENDER_NONCE_OID;
132  attributes.customAttributes[2].oid.length = sizeof(SCEP_SENDER_NONCE_OID);
133  attributes.customAttributes[2].type = ASN1_TYPE_OCTET_STRING;
134  attributes.customAttributes[2].data.value = context->senderNonce;
135  attributes.customAttributes[2].data.length = SCEP_NONCE_SIZE;
136 
137  //Select signature algorithm
138  error = scepClientSelectSignatureAlgo(context, &signatureAlgo);
139  //Any error to report?
140  if(error)
141  return error;
142 
143  //Allocate a memory buffer to store X.509 certificate info
144  certInfo = cryptoAllocMem(sizeof(X509CertInfo));
145 
146  //Successful memory allocation?
147  if(certInfo != NULL)
148  {
149  //The certificate will be either the self-signed one matching the PKCS #10
150  //request or the CA-issued one used to authorise a renewal
151  error = x509ParseCertificate(context->cert, context->certLen, certInfo);
152 
153  //Check status code
154  if(!error)
155  {
156  //During the certificate-enrolment process, the client must use the
157  //selected certificate's key when signing the CMS envelope. This
158  //certificate will be either the self-signed one matching the PKCS #10
159  //request or the CA-issued one used to authorise a renewal (refer to
160  //RFC 8894, section 2.3)
161  error = pkcs7GenerateSignedData(context->prngAlgo,
162  context->prngContext, output, n, certInfo, &attributes, NULL,
163  &signatureAlgo, &context->rsaPrivateKey, output, &n);
164  }
165 
166  //Release previously allocated memory
167  cryptoFreeMem(certInfo);
168  }
169  else
170  {
171  //Failed to allocate memory
172  error = ERROR_OUT_OF_MEMORY;
173  }
174 
175  //Any error to report?
176  if(error)
177  return error;
178 
179  //The general syntax for content exchanged between entities associates a
180  //content type with content (refer to RFC 2315, section 7)
181  osMemset(&contentInfo, 0, sizeof(Pkcs7ContentInfo));
183  contentInfo.contentType.length = sizeof(PKCS7_SIGNED_DATA_OID);
184  contentInfo.content.value = output;
185  contentInfo.content.length = n;
186 
187  //Format ContentInfo structure
188  error = pkcs7FormatContentInfo(&contentInfo, output, &n);
189  //Any error to report?
190  if(error)
191  return error;
192 
193  //Debug message
194  TRACE_DEBUG("pkiMessage (%" PRIuSIZE " bytes):\r\n", n);
195  asn1DumpObject(output, n, 0);
196 
197  //Total length of the ASN.1 structure
198  *written = n;
199 
200  //Successful processing
201  return NO_ERROR;
202 }
203 
204 
205 /**
206  * @brief Format pkcsPKIEnvelope structure
207  * @param[in] context Pointer to the SCEP client context
208  * @param[in] messageType SCEP message type
209  * @param[out] output Buffer where to format the pkcsPKIEnvelope structure
210  * @param[out] written Length of the resulting pkcsPKIEnvelope structure
211  * @return Error code
212  **/
213 
215  ScepMessageType messageType, uint8_t *output, size_t *written)
216 {
217  error_t error;
218  size_t n;
219  X509CertInfo *certInfo;
220  Pkcs7ContentInfo contentInfo;
221  Pkcs7ContentEncrAlgo contentEncrAlgo;
222 
223  //Check the length of the CSR
224  if(context->csrLen == 0)
225  return ERROR_INVALID_CSR;
226 
227  //Select content encryption algorithm
228  error = scepClientSelectContentEncrAlgo(context, &contentEncrAlgo);
229  //Any error to report?
230  if(error)
231  return error;
232 
233  //Check SCEP message type
234  if(messageType == SCEP_MSG_TYPE_PKCS_REQ ||
235  messageType == SCEP_MSG_TYPE_RENEWAL_REQ)
236  {
237  //The messageData for this type consists of a PKCS #10 certificate
238  //request (refer to RFC 8894, section 3.3.1)
239  osMemcpy(context->buffer, context->csr, context->csrLen);
240  n = context->csrLen;
241  }
242  else if(messageType == SCEP_MSG_TYPE_CERT_POLL)
243  {
244  //The messageData for this type consists of an IssuerAndSubject (refer
245  //to RFC 8894, section 3.3.3)
246  error = scepClientFormatIssuerAndSubject(context, output, &n);
247  }
248  else
249  {
250  //Unknown message type
251  error = ERROR_INVALID_TYPE;
252  }
253 
254  //Any error to report?
255  if(error)
256  return error;
257 
258  //Allocate a memory buffer to store X.509 certificate info
259  certInfo = cryptoAllocMem(sizeof(X509CertInfo));
260 
261  //Successful memory allocation?
262  if(certInfo != NULL)
263  {
264  //Parse CA certificate
265  error = scepClientParseCaCert(context, certInfo);
266 
267  //Check status code
268  if(!error)
269  {
270  //Encrypt enveloped-data content
271  error = pkcs7EncryptEnvelopedData(context->prngAlgo,
272  context->prngContext, certInfo, &contentEncrAlgo, context->buffer,
273  n, output, &n);
274  }
275 
276  //Release previously allocated memory
277  cryptoFreeMem(certInfo);
278  }
279  else
280  {
281  //Failed to allocate memory
282  error = ERROR_OUT_OF_MEMORY;
283  }
284 
285  //Any error to report?
286  if(error)
287  return error;
288 
289  //The general syntax for content exchanged between entities associates a
290  //content type with content (refer to RFC 2315, section 7)
292  contentInfo.contentType.length = sizeof(PKCS7_ENVELOPED_DATA_OID);
293  contentInfo.content.value = output;
294  contentInfo.content.length = n;
295 
296  //Format ContentInfo structure
297  error = pkcs7FormatContentInfo(&contentInfo, output, &n);
298  //Any error to report?
299  if(error)
300  return error;
301 
302  //Debug message
303  TRACE_DEBUG("pkcsPKIEnvelope (%" PRIuSIZE " bytes):\r\n", n);
304  asn1DumpObject(output, n, 0);
305 
306  //Total length of the ASN.1 structure
307  *written = n;
308 
309  //Successful processing
310  return NO_ERROR;
311 }
312 
313 
314 /**
315  * @brief Format IssuerAndSubject structure
316  * @param[in] context Pointer to the SCEP client context
317  * @param[out] output Buffer where to format the ASN.1 structure
318  * @param[out] written Length of the resulting ASN.1 structure
319  * @return Error code
320  **/
321 
323  uint8_t *output, size_t *written)
324 {
325  error_t error;
326  size_t n;
327  size_t length;
328  uint8_t *p;
329  Asn1Tag tag;
330  X509CsrInfo *csrInfo;
331  X509CertificateInfo *certInfo;
332 
333  //Point to the buffer where to write the ASN.1 structure
334  p = output;
335  //Length of the ASN.1 structure
336  length = 0;
337 
338  //Allocate a memory buffer to store X.509 certificate info
339  certInfo = cryptoAllocMem(sizeof(X509CertInfo));
340 
341  //Successful memory allocation?
342  if(certInfo != NULL)
343  {
344  //Parse CA certificate
345  error = scepClientParseCaCert(context, certInfo);
346 
347  //Check status code
348  if(!error)
349  {
350  //Format issuer field
351  error = x509FormatName(&certInfo->tbsCert.subject, p, &n);
352  }
353 
354  //Check status code
355  if(!error)
356  {
357  //Advance data pointer
358  ASN1_INC_POINTER(p, n);
359  length += n;
360  }
361 
362  //Release previously allocated memory
363  cryptoFreeMem(certInfo);
364  }
365  else
366  {
367  //Failed to allocate memory
368  error = ERROR_OUT_OF_MEMORY;
369  }
370 
371  //Any error to report?
372  if(error)
373  return error;
374 
375  //Allocate a memory buffer to store CSR info
376  csrInfo = cryptoAllocMem(sizeof(X509CsrInfo));
377 
378  //Successful memory allocation?
379  if(csrInfo != NULL)
380  {
381  //Parse the PKCS #10 certificate request
382  error = x509ParseCsr(context->csr, context->csrLen, csrInfo);
383 
384  //Check status code
385  if(!error)
386  {
387  //Format subject field
388  error = x509FormatName(&csrInfo->certReqInfo.subject, p, &n);
389  }
390 
391  //Check status code
392  if(!error)
393  {
394  //Advance data pointer
395  ASN1_INC_POINTER(p, n);
396  length += n;
397  }
398 
399  //Release previously allocated memory
400  cryptoFreeMem(csrInfo);
401  }
402  else
403  {
404  //Failed to allocate memory
405  error = ERROR_OUT_OF_MEMORY;
406  }
407 
408  //Any error to report?
409  if(error)
410  return error;
411 
412  //The IssuerAndSubject structure is encapsulated within a sequence
413  tag.constructed = TRUE;
416  tag.length = length;
417 
418  //Write the corresponding ASN.1 tag
419  error = asn1InsertHeader(&tag, output, &n);
420  //Any error to report?
421  if(error)
422  return error;
423 
424  //Total number of bytes that have been written
425  *written = tag.totalLength;
426 
427  //Successful processing
428  return NO_ERROR;
429 }
430 
431 #endif
@ SCEP_MSG_TYPE_PKCS_REQ
PKCSReq.
Definition: scep_common.h:56
X.509 certificate parsing.
error_t scepClientSelectContentEncrAlgo(ScepClientContext *context, Pkcs7ContentEncrAlgo *contentEncrAlgo)
Content encryption algorithm selection.
SCEP request generation.
#define ScepClientContext
Definition: scep_client.h:165
uint8_t p
Definition: ndp.h:300
#define TRUE
Definition: os_port.h:50
error_t x509ParseCertificate(const uint8_t *data, size_t length, X509CertInfo *certInfo)
Parse a X.509 certificate.
error_t asn1InsertHeader(Asn1Tag *tag, uint8_t *data, size_t *written)
Insert an ASN.1 tag header.
Definition: asn1.c:643
uint8_t attributes[]
Definition: radius.h:88
error_t asn1DumpObject(const uint8_t *data, size_t length, uint_t level)
Display an ASN.1 data object.
Definition: asn1.c:999
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
void convertUnixTimeToDate(time_t t, DateTime *date)
Convert Unix timestamp to date.
Definition: date_time.c:204
Content information.
Definition: pkcs7_common.h:317
error_t x509ParseCsr(const uint8_t *data, size_t length, X509CsrInfo *csrInfo)
Parse a CSR (Certificate Signing Request)
error_t pkcs7FormatContentInfo(const Pkcs7ContentInfo *contentInfo, uint8_t *output, size_t *written)
Format contentInfo structure.
Definition: pkcs7_format.c:57
#define osStrlen(s)
Definition: os_port.h:168
X.509 certificate formatting.
Content encryption algorithm.
Definition: pkcs7_common.h:328
size_t totalLength
Definition: asn1.h:111
size_t length
Definition: asn1.h:109
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
X.509 certificate.
Definition: x509_common.h:1119
error_t
Error codes.
Definition: error.h:43
#define osSprintf(dest,...)
Definition: os_port.h:234
X509OctetString contentType
Definition: pkcs7_common.h:318
const uint8_t SCEP_TRANSACTION_ID_OID[10]
Definition: scep_common.c:52
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:52
const uint8_t SCEP_MESSAGE_TYPE_OID[10]
Definition: scep_common.c:42
error_t scepClientFormatPkiMessage(ScepClientContext *context, ScepMessageType messageType, uint8_t *output, size_t *written)
Format PKI message.
ASN.1 tag.
Definition: asn1.h:105
#define ASN1_INC_POINTER(p, n)
Definition: asn1.h:58
@ SCEP_MSG_TYPE_RENEWAL_REQ
RenewalReq.
Definition: scep_common.h:55
error_t scepClientParseCaCert(ScepClientContext *context, X509CertInfo *certInfo)
Parse CA certificate.
#define X509CertificateInfo
Definition: crypto_legacy.h:63
error_t scepClientFormatPkcsPkiEnvelope(ScepClientContext *context, ScepMessageType messageType, uint8_t *output, size_t *written)
Format pkcsPKIEnvelope structure.
X509CertRequestInfo certReqInfo
Definition: x509_common.h:1323
@ ERROR_INVALID_TYPE
Definition: error.h:115
error_t pkcs7GenerateSignedData(const PrngAlgo *prngAlgo, void *prngContext, const uint8_t *content, size_t contentLen, const X509CertInfo *signerCertInfo, const Pkcs7AuthenticatedAttributes *authenticatedAttributes, const Pkcs7UnauthenticatedAttributes *unauthenticatedAttributes, const X509SignAlgoId *signatureAlgo, const void *signerPrivateKey, uint8_t *output, size_t *written)
Generate signed-data content.
uint_t objClass
Definition: asn1.h:107
@ ASN1_TYPE_PRINTABLE_STRING
Definition: asn1.h:86
uint8_t length
Definition: tcp.h:375
@ ERROR_INVALID_CSR
Definition: error.h:309
PKCS #7 message encryption.
const uint8_t PKCS7_DATA_OID[9]
Definition: pkcs7_common.c:50
SCEP client.
@ ASN1_TYPE_OCTET_STRING
Definition: asn1.h:75
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
uint8_t n
X509OctetString content
Definition: pkcs7_common.h:319
error_t x509FormatName(const X509Name *name, uint8_t *output, size_t *written)
Format Name structure.
#define cryptoFreeMem(p)
Definition: crypto.h:833
const uint8_t PKCS7_SIGNED_DATA_OID[9]
Definition: pkcs7_common.c:52
#define SCEP_NONCE_SIZE
Definition: scep_common.h:39
error_t scepClientSelectSignatureAlgo(ScepClientContext *context, X509SignAlgoId *signatureAlgo)
Signature algorithm selection.
const uint8_t SCEP_SENDER_NONCE_OID[10]
Definition: scep_common.c:48
bool_t constructed
Definition: asn1.h:106
#define cryptoAllocMem(size)
Definition: crypto.h:828
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:83
const uint8_t * value
Definition: x509_common.h:702
ScepMessageType
SCEP message types.
Definition: scep_common.h:52
@ SCEP_MSG_TYPE_CERT_POLL
CertPoll.
Definition: scep_common.h:57
PKCS #7 signature generation.
error_t scepClientFormatIssuerAndSubject(ScepClientContext *context, uint8_t *output, size_t *written)
Format IssuerAndSubject structure.
Authenticated attributes.
Definition: pkcs7_common.h:237
const uint8_t PKCS7_ENVELOPED_DATA_OID[9]
Definition: pkcs7_common.c:54
PKCS #7 message formatting.
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
CSR (Certificate Signing Request)
Definition: x509_common.h:1322
Helper functions for SCEP client.
CSR (Certificate Signing Request) parsing.
__weak_func time_t getCurrentUnixTime(void)
Get current time.
Definition: date_time.c:186
Signature algorithm identifier.
Definition: x509_common.h:1088
@ NO_ERROR
Success.
Definition: error.h:44
error_t pkcs7EncryptEnvelopedData(const PrngAlgo *prngAlgo, void *prngContext, const X509CertInfo *recipientCertInfo, const Pkcs7ContentEncrAlgo *contentEncrAlgo, const uint8_t *plaintext, size_t plaintextLen, uint8_t *output, size_t *written)
Encrypt enveloped-data content.
Definition: pkcs7_encrypt.c:60
Debugging facilities.
uint_t objType
Definition: asn1.h:108
ASN.1 (Abstract Syntax Notation One)