est_client_operations.c
Go to the documentation of this file.
1 /**
2  * @file est_client_operations.c
3  * @brief EST operations
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2024-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneEST 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.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL EST_TRACE_LEVEL
33 
34 //Dependencies
35 #include "est/est_client.h"
40 #include "debug.h"
41 
42 //Check crypto library configuration
43 #if (EST_CLIENT_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Perform "cacerts" operation
48  * @param[in] context Pointer to the EST 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 == EST_REQ_STATE_INIT)
64  {
65  //Debug message
66  TRACE_INFO("Generating cacerts request...\r\n");
67 
68  //Update HTTP request state
69  context->requestState = EST_REQ_STATE_FORMAT_HEADER;
70  }
71  else if(context->requestState == EST_REQ_STATE_FORMAT_HEADER)
72  {
73  //EST clients request the EST CA TA database information of the CA
74  //with an HTTPS GET message using an operation path of "/cacerts"
75  //(refer to RFC 7030, section 4.1.2)
76  error = estClientFormatRequestHeader(context, "GET", "cacerts");
77 
78  //Check status code
79  if(!error)
80  {
81  //Debug message
82  TRACE_INFO("Sending cacerts request...\r\n");
83 
84  //Update HTTP request state
85  context->requestState = EST_REQ_STATE_SEND_HEADER;
86  }
87  }
88  else if(context->requestState == EST_REQ_STATE_SEND_HEADER ||
89  context->requestState == EST_REQ_STATE_SEND_BODY ||
90  context->requestState == EST_REQ_STATE_RECEIVE_HEADER ||
91  context->requestState == EST_REQ_STATE_PARSE_HEADER ||
92  context->requestState == EST_REQ_STATE_RECEIVE_BODY ||
93  context->requestState == EST_REQ_STATE_CLOSE_BODY)
94  {
95  //Perform HTTP request/response transaction
96  error = estClientSendRequest(context);
97  }
98  else if(context->requestState == EST_REQ_STATE_COMPLETE)
99  {
100  //Debug message
101  TRACE_INFO("Parsing cacerts response...\r\n");
102 
103  //Parse the body of the HTTP response
104  error = estClientParseGetCaCertsResponse(context);
105 
106  //The HTTP transaction is complete
107  context->requestState = EST_REQ_STATE_INIT;
108  break;
109  }
110  else
111  {
112  //Invalid state
113  error = ERROR_WRONG_STATE;
114  }
115  }
116 
117  //Return status code
118  return error;
119 }
120 
121 
122 /**
123  * @brief Perform "simpleenroll" operation
124  * @param[in] context Pointer to the EST client context
125  * @return Error code
126  **/
127 
129 {
130  error_t error;
131 
132  //Initialize variables
133  error = NO_ERROR;
134 
135  //Perform HTTP request
136  while(!error)
137  {
138  //Check HTTP request state
139  if(context->requestState == EST_REQ_STATE_INIT)
140  {
141  //Debug message
142  TRACE_INFO("Generating simpleenroll request...\r\n");
143 
144  //Update HTTP request state
145  context->requestState = EST_REQ_STATE_FORMAT_BODY;
146  }
147  else if(context->requestState == EST_REQ_STATE_FORMAT_BODY)
148  {
149  //When HTTPS POSTing to "/simpleenroll", the client must include a
150  //Simple PKI Request as specified in CMC (refer to RFC 7030,
151  //section 4.2.1)
152  error = estClientFormatPkiRequest(context, context->buffer,
153  &context->bufferLen);
154 
155  //Check status code
156  if(!error)
157  {
158  //Update HTTP request state
159  context->requestState = EST_REQ_STATE_FORMAT_HEADER;
160  }
161  }
162  else if(context->requestState == EST_REQ_STATE_FORMAT_HEADER)
163  {
164  //EST clients request a certificate from the EST server with an HTTPS
165  //POST using the operation path value of "/simpleenroll" (refer to
166  //RFC 7030, section 4.2)
167  error = estClientFormatRequestHeader(context, "POST", "simpleenroll");
168 
169  //Check status code
170  if(!error)
171  {
172  //Debug message
173  TRACE_INFO("Sending simpleenroll request...\r\n");
174 
175  //Update HTTP request state
176  context->requestState = EST_REQ_STATE_SEND_HEADER;
177  }
178  }
179  else if(context->requestState == EST_REQ_STATE_SEND_HEADER ||
180  context->requestState == EST_REQ_STATE_SEND_BODY ||
181  context->requestState == EST_REQ_STATE_RECEIVE_HEADER ||
182  context->requestState == EST_REQ_STATE_PARSE_HEADER ||
183  context->requestState == EST_REQ_STATE_RECEIVE_BODY ||
184  context->requestState == EST_REQ_STATE_CLOSE_BODY)
185  {
186  //Perform HTTP request/response transaction
187  error = estClientSendRequest(context);
188  }
189  else if(context->requestState == EST_REQ_STATE_COMPLETE)
190  {
191  //Invalid authentication credentials?
192  if(context->statusCode == 401)
193  {
194  //In response to the initial HTTP POST attempt, the server requests
195  //WWW-Authenticate from the client
196  if(context->selectedAuthMode == HTTP_AUTH_MODE_NONE &&
197  context->httpClientContext.authParams.selectedMode != HTTP_AUTH_MODE_NONE)
198  {
199  //In the subsequent HTTP POST, the username/password is included
200  context->requestState = EST_REQ_STATE_FORMAT_HEADER;
201  }
202  else
203  {
204  //Report an error
206  }
207  }
208  else
209  {
210  //Debug message
211  TRACE_INFO("Parsing simpleenroll response...\r\n");
212 
213  //Parse the body of the HTTP response
214  error = estClientParseSimpleEnrollResponse(context);
215 
216  //The HTTP transaction is complete
217  context->requestState = EST_REQ_STATE_INIT;
218  break;
219  }
220  }
221  else
222  {
223  //Invalid state
224  error = ERROR_WRONG_STATE;
225  }
226  }
227 
228  //Return status code
229  return error;
230 }
231 
232 
233 /**
234  * @brief Perform "simplereenroll" operation
235  * @param[in] context Pointer to the EST client context
236  * @return Error code
237  **/
238 
240 {
241  error_t error;
242 
243  //Initialize variables
244  error = NO_ERROR;
245 
246  //Perform HTTP request
247  while(!error)
248  {
249  //Check HTTP request state
250  if(context->requestState == EST_REQ_STATE_INIT)
251  {
252  //Debug message
253  TRACE_INFO("Generating simplereenroll request...\r\n");
254 
255  //Update HTTP request state
256  context->requestState = EST_REQ_STATE_FORMAT_BODY;
257  }
258  else if(context->requestState == EST_REQ_STATE_FORMAT_BODY)
259  {
260  //A certificate request employs the same format as the "simpleenroll"
261  //request (refer to RFC 7030, section 4.2.2)
262  error = estClientFormatPkiRequest(context, context->buffer,
263  &context->bufferLen);
264 
265  //Check status code
266  if(!error)
267  {
268  //Update HTTP request state
269  context->requestState = EST_REQ_STATE_FORMAT_HEADER;
270  }
271  }
272  else if(context->requestState == EST_REQ_STATE_FORMAT_HEADER)
273  {
274  //EST clients request a renew/rekey of existing certificates with an
275  //HTTP POST using the operation path value of "/simplereenroll" (refer
276  //to RFC 7030, section 4.2)
277  error = estClientFormatRequestHeader(context, "POST",
278  "simplereenroll");
279 
280  //Check status code
281  if(!error)
282  {
283  //Debug message
284  TRACE_INFO("Sending simplereenroll request...\r\n");
285 
286  //Update HTTP request state
287  context->requestState = EST_REQ_STATE_SEND_HEADER;
288  }
289  }
290  else if(context->requestState == EST_REQ_STATE_SEND_HEADER ||
291  context->requestState == EST_REQ_STATE_SEND_BODY ||
292  context->requestState == EST_REQ_STATE_RECEIVE_HEADER ||
293  context->requestState == EST_REQ_STATE_PARSE_HEADER ||
294  context->requestState == EST_REQ_STATE_RECEIVE_BODY ||
295  context->requestState == EST_REQ_STATE_CLOSE_BODY)
296  {
297  //Perform HTTP request/response transaction
298  error = estClientSendRequest(context);
299  }
300  else if(context->requestState == EST_REQ_STATE_COMPLETE)
301  {
302  //Invalid authentication credentials?
303  if(context->statusCode == 401)
304  {
305  //In response to the initial HTTP POST attempt, the server requests
306  //WWW-Authenticate from the client
307  if(context->selectedAuthMode == HTTP_AUTH_MODE_NONE &&
308  context->httpClientContext.authParams.selectedMode != HTTP_AUTH_MODE_NONE)
309  {
310  //In the subsequent HTTP POST, the username/password is included
311  context->requestState = EST_REQ_STATE_FORMAT_HEADER;
312  }
313  else
314  {
315  //Report an error
317  }
318  }
319  else
320  {
321  //Debug message
322  TRACE_INFO("Parsing simplereenroll response...\r\n");
323 
324  //Parse the body of the HTTP response
325  error = estClientParseSimpleEnrollResponse(context);
326 
327  //The HTTP transaction is complete
328  context->requestState = EST_REQ_STATE_INIT;
329  break;
330  }
331  }
332  else
333  {
334  //Invalid state
335  error = ERROR_WRONG_STATE;
336  }
337  }
338 
339  //Return status code
340  return error;
341 }
342 
343 #endif
HTTP transport mechanism.
error_t estClientParseSimpleEnrollResponse(EstClientContext *context)
Parse "simpleenroll" or "simplereenroll" response.
EST client.
@ EST_REQ_STATE_FORMAT_BODY
Definition: est_client.h:193
error_t estClientSendRequest(EstClientContext *context)
Send HTTP request.
@ EST_REQ_STATE_COMPLETE
Definition: est_client.h:199
EST request generation.
error_t estClientSendSimpleReEnroll(EstClientContext *context)
Perform "simplereenroll" operation.
@ ERROR_WRONG_STATE
Definition: error.h:210
error_t
Error codes.
Definition: error.h:43
@ EST_REQ_STATE_PARSE_HEADER
Definition: est_client.h:196
error_t estClientParseGetCaCertsResponse(EstClientContext *context)
Parse "cacerts" response.
@ EST_REQ_STATE_FORMAT_HEADER
Definition: est_client.h:191
EST response parsing.
@ EST_REQ_STATE_RECEIVE_HEADER
Definition: est_client.h:195
#define TRACE_INFO(...)
Definition: debug.h:105
@ EST_REQ_STATE_CLOSE_BODY
Definition: est_client.h:198
@ EST_REQ_STATE_RECEIVE_BODY
Definition: est_client.h:197
@ EST_REQ_STATE_SEND_BODY
Definition: est_client.h:194
@ ERROR_AUTHENTICATION_FAILED
Definition: error.h:69
@ EST_REQ_STATE_INIT
Definition: est_client.h:190
error_t estClientSendCaCerts(EstClientContext *context)
Perform "cacerts" operation.
error_t estClientSendSimpleEnroll(EstClientContext *context)
Perform "simpleenroll" operation.
@ EST_REQ_STATE_SEND_HEADER
Definition: est_client.h:192
error_t estClientFormatRequestHeader(EstClientContext *context, const char_t *method, const char_t *operation)
Format HTTP request header.
@ HTTP_AUTH_MODE_NONE
Definition: http_common.h:73
error_t estClientFormatPkiRequest(EstClientContext *context, uint8_t *output, size_t *written)
Format PKI request.
#define EstClientContext
Definition: est_client.h:159
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.