scep_client_operations.c
Go to the documentation of this file.
1 /**
2  * @file scep_client_operations.c
3  * @brief SCEP operations
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"
40 #include "debug.h"
41 
42 //Check crypto library configuration
43 #if (SCEP_CLIENT_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Perform GetCACaps operation
48  * @param[in] context Pointer to the SCEP client context
49  * @return Error code
50  **/
51 
53 {
54  error_t error;
55 
56  //Initialize variables
57  error = NO_ERROR;
58 
59  //Perform HTTP request
60  while(!error)
61  {
62  //Check HTTP request state
63  if(context->requestState == SCEP_REQ_STATE_INIT)
64  {
65  //Debug message
66  TRACE_INFO("Generating GetCACaps request...\r\n");
67 
68  //Update HTTP request state
69  context->requestState = SCEP_REQ_STATE_FORMAT_HEADER;
70  }
71  else if(context->requestState == SCEP_REQ_STATE_FORMAT_HEADER)
72  {
73  //This message requests capabilities from a CA (refer to RFC 8894,
74  //section 3.5.1)
75  error = scepClientFormatRequestHeader(context, "GET", "GetCACaps");
76 
77  //Check status code
78  if(!error)
79  {
80  //Debug message
81  TRACE_INFO("Sending GetCACaps request...\r\n");
82 
83  //Update HTTP request state
84  context->requestState = SCEP_REQ_STATE_SEND_HEADER;
85  }
86  }
87  else if(context->requestState == SCEP_REQ_STATE_SEND_HEADER ||
88  context->requestState == SCEP_REQ_STATE_SEND_BODY ||
89  context->requestState == SCEP_REQ_STATE_RECEIVE_HEADER ||
90  context->requestState == SCEP_REQ_STATE_PARSE_HEADER ||
91  context->requestState == SCEP_REQ_STATE_RECEIVE_BODY ||
92  context->requestState == SCEP_REQ_STATE_CLOSE_BODY)
93  {
94  //Perform HTTP request/response transaction
95  error = scepClientSendRequest(context);
96  }
97  else if(context->requestState == SCEP_REQ_STATE_COMPLETE)
98  {
99  //Debug message
100  TRACE_INFO("Parsing GetCACaps response...\r\n");
101 
102  //Parse the body of the HTTP response
103  error = scepClientParseGetCaCapsResponse(context);
104 
105  //The HTTP transaction is complete
106  context->requestState = SCEP_REQ_STATE_INIT;
107  break;
108  }
109  else
110  {
111  //Invalid state
112  error = ERROR_WRONG_STATE;
113  }
114  }
115 
116  //Return status code
117  return error;
118 }
119 
120 
121 /**
122  * @brief Perform GetCACert operation
123  * @param[in] context Pointer to the SCEP client context
124  * @return Error code
125  **/
126 
128 {
129  error_t error;
130 
131  //Initialize variables
132  error = NO_ERROR;
133 
134  //Perform HTTP request
135  while(!error)
136  {
137  //Check HTTP request state
138  if(context->requestState == SCEP_REQ_STATE_INIT)
139  {
140  //Debug message
141  TRACE_INFO("Generating GetCACert request...\r\n");
142 
143  //Update HTTP request state
144  context->requestState = SCEP_REQ_STATE_FORMAT_HEADER;
145  }
146  else if(context->requestState == SCEP_REQ_STATE_FORMAT_HEADER)
147  {
148  //To get the CA certificate(s), the client sends a GetCACert message
149  //to the CA (refer to RFC 8894, section 4.2)
150  error = scepClientFormatRequestHeader(context, "GET", "GetCACert");
151 
152  //Check status code
153  if(!error)
154  {
155  //Debug message
156  TRACE_INFO("Sending GetCACert request...\r\n");
157 
158  //Update HTTP request state
159  context->requestState = SCEP_REQ_STATE_SEND_HEADER;
160  }
161  }
162  else if(context->requestState == SCEP_REQ_STATE_SEND_HEADER ||
163  context->requestState == SCEP_REQ_STATE_SEND_BODY ||
164  context->requestState == SCEP_REQ_STATE_RECEIVE_HEADER ||
165  context->requestState == SCEP_REQ_STATE_PARSE_HEADER ||
166  context->requestState == SCEP_REQ_STATE_RECEIVE_BODY ||
167  context->requestState == SCEP_REQ_STATE_CLOSE_BODY)
168  {
169  //Perform HTTP request/response transaction
170  error = scepClientSendRequest(context);
171  }
172  else if(context->requestState == SCEP_REQ_STATE_COMPLETE)
173  {
174  //Debug message
175  TRACE_INFO("Parsing GetCaCert response...\r\n");
176 
177  //Parse the body of the HTTP response
178  error = scepClientParseGetCaCertResponse(context);
179 
180  //The HTTP transaction is complete
181  context->requestState = SCEP_REQ_STATE_INIT;
182  break;
183  }
184  else
185  {
186  //Invalid state
187  error = ERROR_WRONG_STATE;
188  }
189  }
190 
191  //Return status code
192  return error;
193 }
194 
195 
196 /**
197  * @brief Perform PKCSReq operation
198  * @param[in] context Pointer to the SCEP client context
199  * @return Error code
200  **/
201 
203 {
204  error_t error;
205 
206  //Initialize variables
207  error = NO_ERROR;
208 
209  //Perform HTTP request
210  while(!error)
211  {
212  //Check HTTP request state
213  if(context->requestState == SCEP_REQ_STATE_INIT)
214  {
215  //Debug message
216  TRACE_INFO("Generating PKCSReq request...\r\n");
217 
218  //Update HTTP request state
219  context->requestState = SCEP_REQ_STATE_FORMAT_BODY;
220  }
221  else if(context->requestState == SCEP_REQ_STATE_FORMAT_BODY)
222  {
223  //The PKCSReq message is used to perform a certificate enrolment
224  //transaction (refer to RFC 8555, section 4.3)
226  context->buffer, &context->bufferLen);
227 
228  //Check status code
229  if(!error)
230  {
231  //Update HTTP request state
232  context->requestState = SCEP_REQ_STATE_FORMAT_HEADER;
233  }
234  }
235  else if(context->requestState == SCEP_REQ_STATE_FORMAT_HEADER)
236  {
237  //Check is the the remote CA supports POST
238  if((context->caCaps & SCEP_CA_CAPS_POST_PKI_OPERATION) != 0)
239  {
240  //If the remote CA supports POST, the CMS-encoded SCEP messages
241  //must be sent via HTTP POST instead of HTTP GET (refer to RFC 8894,
242  //section 4.1)
243  error = scepClientFormatRequestHeader(context, "POST",
244  "PKIOperation");
245  }
246  else
247  {
248  //For historical reasons, implementations may support communications
249  //of binary data via HTTP GET (refer to RFC 8894, section 2.9)
251  }
252 
253  //Check status code
254  if(!error)
255  {
256  //Debug message
257  TRACE_INFO("Sending PKCSReq request...\r\n");
258 
259  //Update HTTP request state
260  context->requestState = SCEP_REQ_STATE_SEND_HEADER;
261  }
262  }
263  else if(context->requestState == SCEP_REQ_STATE_SEND_HEADER ||
264  context->requestState == SCEP_REQ_STATE_SEND_BODY ||
265  context->requestState == SCEP_REQ_STATE_RECEIVE_HEADER ||
266  context->requestState == SCEP_REQ_STATE_PARSE_HEADER ||
267  context->requestState == SCEP_REQ_STATE_RECEIVE_BODY ||
268  context->requestState == SCEP_REQ_STATE_CLOSE_BODY)
269  {
270  //Perform HTTP request/response transaction
271  error = scepClientSendRequest(context);
272  }
273  else if(context->requestState == SCEP_REQ_STATE_COMPLETE)
274  {
275  //Debug message
276  TRACE_INFO("Parsing CertRep response...\r\n");
277 
278  //Parse CertRep message
279  error = scepClientParseCertResponse(context);
280 
281  //The HTTP transaction is complete
282  context->requestState = SCEP_REQ_STATE_INIT;
283  break;
284  }
285  else
286  {
287  //Invalid state
288  error = ERROR_WRONG_STATE;
289  }
290  }
291 
292  //Return status code
293  return error;
294 }
295 
296 
297 /**
298  * @brief Perform RenewalReq operation
299  * @param[in] context Pointer to the SCEP client context
300  * @return Error code
301  **/
302 
304 {
305  error_t error;
306 
307  //Initialize variables
308  error = NO_ERROR;
309 
310  //Perform HTTP request
311  while(!error)
312  {
313  //Check HTTP request state
314  if(context->requestState == SCEP_REQ_STATE_INIT)
315  {
316  //Debug message
317  TRACE_INFO("Generating RenewalReq request...\r\n");
318 
319  //Update HTTP request state
320  context->requestState = SCEP_REQ_STATE_FORMAT_BODY;
321  }
322  else if(context->requestState == SCEP_REQ_STATE_FORMAT_BODY)
323  {
324  //The RenewalReq message is used to perform a certificate renewal
325  //transaction (refer to RFC 8555, section 4.3)
327  context->buffer, &context->bufferLen);
328 
329  //Check status code
330  if(!error)
331  {
332  //Update HTTP request state
333  context->requestState = SCEP_REQ_STATE_FORMAT_HEADER;
334  }
335  }
336  else if(context->requestState == SCEP_REQ_STATE_FORMAT_HEADER)
337  {
338  //Check is the the remote CA supports POST
339  if((context->caCaps & SCEP_CA_CAPS_POST_PKI_OPERATION) != 0)
340  {
341  //If the remote CA supports POST, the CMS-encoded SCEP messages
342  //must be sent via HTTP POST instead of HTTP GET (refer to RFC 8894,
343  //section 4.1)
344  error = scepClientFormatRequestHeader(context, "POST",
345  "PKIOperation");
346  }
347  else
348  {
349  //For historical reasons, implementations may support communications
350  //of binary data via HTTP GET (refer to RFC 8894, section 2.9)
352  }
353 
354  //Check status code
355  if(!error)
356  {
357  //Debug message
358  TRACE_INFO("Sending RenewalReq request...\r\n");
359 
360  //Update HTTP request state
361  context->requestState = SCEP_REQ_STATE_SEND_HEADER;
362  }
363  }
364  else if(context->requestState == SCEP_REQ_STATE_SEND_HEADER ||
365  context->requestState == SCEP_REQ_STATE_SEND_BODY ||
366  context->requestState == SCEP_REQ_STATE_RECEIVE_HEADER ||
367  context->requestState == SCEP_REQ_STATE_PARSE_HEADER ||
368  context->requestState == SCEP_REQ_STATE_RECEIVE_BODY ||
369  context->requestState == SCEP_REQ_STATE_CLOSE_BODY)
370  {
371  //Perform HTTP request/response transaction
372  error = scepClientSendRequest(context);
373  }
374  else if(context->requestState == SCEP_REQ_STATE_COMPLETE)
375  {
376  //Debug message
377  TRACE_INFO("Parsing CertRep response...\r\n");
378 
379  //Parse CertRep message
380  error = scepClientParseCertResponse(context);
381 
382  //The HTTP transaction is complete
383  context->requestState = SCEP_REQ_STATE_INIT;
384  break;
385  }
386  else
387  {
388  //Invalid state
389  error = ERROR_WRONG_STATE;
390  }
391  }
392 
393  //Return status code
394  return error;
395 }
396 
397 
398 /**
399  * @brief Perform CertPoll operation
400  * @param[in] context Pointer to the SCEP client context
401  * @return Error code
402  **/
403 
405 {
406  error_t error;
407 
408  //Initialize variables
409  error = NO_ERROR;
410 
411  //Perform HTTP request
412  while(!error)
413  {
414  //Check HTTP request state
415  if(context->requestState == SCEP_REQ_STATE_INIT)
416  {
417  //Debug message
418  TRACE_INFO("Generating CertPoll request...\r\n");
419 
420  //Update HTTP request state
421  context->requestState = SCEP_REQ_STATE_FORMAT_BODY;
422  }
423  else if(context->requestState == SCEP_REQ_STATE_FORMAT_BODY)
424  {
425  //The CertPoll message is used for certificate polling (refer to
426  //RFC 8555, section 3.3.3)
428  context->buffer, &context->bufferLen);
429 
430  //Check status code
431  if(!error)
432  {
433  //Update HTTP request state
434  context->requestState = SCEP_REQ_STATE_FORMAT_HEADER;
435  }
436  }
437  else if(context->requestState == SCEP_REQ_STATE_FORMAT_HEADER)
438  {
439  //Check is the the remote CA supports POST
440  if((context->caCaps & SCEP_CA_CAPS_POST_PKI_OPERATION) != 0)
441  {
442  //If the remote CA supports POST, the CMS-encoded SCEP messages
443  //must be sent via HTTP POST instead of HTTP GET (refer to RFC 8894,
444  //section 4.1)
445  error = scepClientFormatRequestHeader(context, "POST",
446  "PKIOperation");
447  }
448  else
449  {
450  //For historical reasons, implementations may support communications
451  //of binary data via HTTP GET (refer to RFC 8894, section 2.9)
453  }
454 
455  //Check status code
456  if(!error)
457  {
458  //Debug message
459  TRACE_INFO("Sending CertPoll request...\r\n");
460 
461  //Update HTTP request state
462  context->requestState = SCEP_REQ_STATE_SEND_HEADER;
463  }
464  }
465  else if(context->requestState == SCEP_REQ_STATE_SEND_HEADER ||
466  context->requestState == SCEP_REQ_STATE_SEND_BODY ||
467  context->requestState == SCEP_REQ_STATE_RECEIVE_HEADER ||
468  context->requestState == SCEP_REQ_STATE_PARSE_HEADER ||
469  context->requestState == SCEP_REQ_STATE_RECEIVE_BODY ||
470  context->requestState == SCEP_REQ_STATE_CLOSE_BODY)
471  {
472  //Perform HTTP request/response transaction
473  error = scepClientSendRequest(context);
474  }
475  else if(context->requestState == SCEP_REQ_STATE_COMPLETE)
476  {
477  //Debug message
478  TRACE_INFO("Parsing CertRep response...\r\n");
479 
480  //Parse CertRep message
481  error = scepClientParseCertResponse(context);
482 
483  //The HTTP transaction is complete
484  context->requestState = SCEP_REQ_STATE_INIT;
485  break;
486  }
487  else
488  {
489  //Invalid state
490  error = ERROR_WRONG_STATE;
491  }
492  }
493 
494  //Return status code
495  return error;
496 }
497 
498 #endif
@ SCEP_MSG_TYPE_PKCS_REQ
PKCSReq.
Definition: scep_common.h:56
error_t scepClientSendCertPoll(ScepClientContext *context)
Perform CertPoll operation.
SCEP request generation.
#define ScepClientContext
Definition: scep_client.h:165
@ SCEP_REQ_STATE_SEND_BODY
Definition: scep_client.h:204
@ SCEP_CA_CAPS_POST_PKI_OPERATION
POSTPKIOperation.
Definition: scep_common.h:99
error_t scepClientSendRenewalReq(ScepClientContext *context)
Perform RenewalReq operation.
@ SCEP_REQ_STATE_RECEIVE_HEADER
Definition: scep_client.h:205
@ SCEP_REQ_STATE_INIT
Definition: scep_client.h:200
@ ERROR_WRONG_STATE
Definition: error.h:210
@ SCEP_REQ_STATE_COMPLETE
Definition: scep_client.h:209
error_t scepClientParseCertResponse(ScepClientContext *context)
Parse CertRep response.
@ SCEP_REQ_STATE_RECEIVE_BODY
Definition: scep_client.h:207
error_t
Error codes.
Definition: error.h:43
@ SCEP_REQ_STATE_PARSE_HEADER
Definition: scep_client.h:206
error_t scepClientParseGetCaCapsResponse(ScepClientContext *context)
Parse GetCACaps response.
@ SCEP_REQ_STATE_SEND_HEADER
Definition: scep_client.h:202
error_t scepClientFormatPkiMessage(ScepClientContext *context, ScepMessageType messageType, uint8_t *output, size_t *written)
Format PKI message.
@ SCEP_MSG_TYPE_RENEWAL_REQ
RenewalReq.
Definition: scep_common.h:55
error_t scepClientParseGetCaCertResponse(ScepClientContext *context)
Parse GetCACert response.
@ SCEP_REQ_STATE_FORMAT_BODY
Definition: scep_client.h:203
#define TRACE_INFO(...)
Definition: debug.h:105
error_t scepClientSendRequest(ScepClientContext *context)
Send HTTP request.
SCEP client.
@ ERROR_UNSUPPORTED_FEATURE
Unsupported feature.
Definition: error.h:58
error_t scepClientSendGetCaCaps(ScepClientContext *context)
Perform GetCACaps operation.
@ SCEP_REQ_STATE_CLOSE_BODY
Definition: scep_client.h:208
@ SCEP_REQ_STATE_FORMAT_HEADER
Definition: scep_client.h:201
error_t scepClientSendPkcsReq(ScepClientContext *context)
Perform PKCSReq operation.
error_t scepClientFormatRequestHeader(ScepClientContext *context, const char_t *method, const char_t *operation)
Format HTTP request header.
SCEP response parsing.
@ SCEP_MSG_TYPE_CERT_POLL
CertPoll.
Definition: scep_common.h:57
error_t scepClientSendGetCaCert(ScepClientContext *context)
Perform GetCACert operation.
HTTP transport mechanism.
SCEP operations.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.