acme_client_nonce.c
Go to the documentation of this file.
1 /**
2  * @file acme_client_nonce.c
3  * @brief Anti-replay nonce management
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneACME 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.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL ACME_TRACE_LEVEL
33 
34 //Dependencies
35 #include "acme/acme_client.h"
36 #include "acme/acme_client_nonce.h"
37 #include "acme/acme_client_misc.h"
38 #include "debug.h"
39 
40 //Check TCP/IP stack configuration
41 #if (ACME_CLIENT_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Send HTTP request (newNonce URL)
46  * @param[in] context Pointer to the ACME client context
47  * @return Error code
48  **/
49 
51 {
52  error_t error;
53 
54  //Initialize variables
55  error = NO_ERROR;
56 
57  //Perform HTTP request
58  while(!error)
59  {
60  //Check HTTP request state
61  if(context->requestState == ACME_REQ_STATE_INIT)
62  {
63  //Debug message
64  TRACE_DEBUG("\r\n");
65  TRACE_DEBUG("################################################################################\r\n");
66  TRACE_DEBUG("## GET NEW NONCE ###############################################################\r\n");
67  TRACE_DEBUG("################################################################################\r\n");
68  TRACE_DEBUG("\r\n");
69 
70  //Check whether the nonce is fresh
71  if(context->nonce[0] != '\0')
72  {
73  //The client has gotten a nonce from a previous request
74  break;
75  }
76  else
77  {
78  //If the nonce is no longer valid, the client must get a fresh nonce
79  context->requestState = ACME_REQ_STATE_FORMAT_HEADER;
80  }
81  }
82  else if(context->requestState == ACME_REQ_STATE_FORMAT_HEADER)
83  {
84  //To get a fresh nonce, the client sends a HEAD request to the newNonce
85  //resource on the server (refer to RFC 8555, section 7.2)
86  error = acmeClientFormatRequestHeader(context, "HEAD",
87  context->directory.newNonce);
88 
89  //Check status code
90  if(!error)
91  {
92  //Update HTTP request state
93  context->requestState = ACME_REQ_STATE_SEND_HEADER;
94  }
95  }
96  else if(context->requestState == ACME_REQ_STATE_SEND_HEADER ||
97  context->requestState == ACME_REQ_STATE_RECEIVE_HEADER ||
98  context->requestState == ACME_REQ_STATE_PARSE_HEADER ||
99  context->requestState == ACME_REQ_STATE_RECEIVE_BODY ||
100  context->requestState == ACME_REQ_STATE_CLOSE_BODY)
101  {
102  //Perform HTTP request/response transaction
103  error = acmeClientSendRequest(context);
104  }
105  else if(context->requestState == ACME_REQ_STATE_PARSE_BODY)
106  {
107  //The response to a HEAD request does not contain a body
108  error = acmeClientParseNewNonceResponse(context);
109 
110  //The HTTP transaction is complete
111  context->requestState = ACME_REQ_STATE_INIT;
112  break;
113  }
114  else
115  {
116  //Invalid state
117  error = ERROR_WRONG_STATE;
118  }
119  }
120 
121  //Return status code
122  return error;
123 }
124 
125 
126 /**
127  * @brief Parse HTTP response (newNonce URL)
128  * @param[in] context Pointer to the ACME client context
129  * @return Error code
130  **/
131 
133 {
134  //Check HTTP status code
135  if(!HTTP_STATUS_CODE_2YZ(context->statusCode))
137 
138  //The server's response must include a Replay-Nonce header field containing
139  //a fresh nonce (refer to RFC 8555, section 7.2)
140  if(context->nonce[0] == '\0')
141  return ERROR_INVALID_RESPONSE;
142 
143  //The response to a HEAD request does not contain a body
144  return NO_ERROR;
145 }
146 
147 #endif
#define HTTP_STATUS_CODE_2YZ(code)
Definition: http_common.h:44
Helper functions for ACME client.
error_t acmeClientSendNewNonceRequest(AcmeClientContext *context)
Send HTTP request (newNonce URL)
@ ACME_REQ_STATE_PARSE_BODY
Definition: acme_client.h:297
Anti-replay nonce management.
@ ERROR_WRONG_STATE
Definition: error.h:209
@ ACME_REQ_STATE_FORMAT_HEADER
Definition: acme_client.h:290
error_t acmeClientSendRequest(AcmeClientContext *context)
Send HTTP request.
@ ERROR_UNEXPECTED_STATUS
Definition: error.h:283
error_t acmeClientFormatRequestHeader(AcmeClientContext *context, const char_t *method, const char_t *url)
Format HTTP request header.
error_t
Error codes.
Definition: error.h:43
@ ACME_REQ_STATE_CLOSE_BODY
Definition: acme_client.h:298
@ ACME_REQ_STATE_INIT
Definition: acme_client.h:289
@ ACME_REQ_STATE_RECEIVE_HEADER
Definition: acme_client.h:294
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define AcmeClientContext
Definition: acme_client.h:248
error_t acmeClientParseNewNonceResponse(AcmeClientContext *context)
Parse HTTP response (newNonce URL)
@ ACME_REQ_STATE_SEND_HEADER
Definition: acme_client.h:291
@ ACME_REQ_STATE_PARSE_HEADER
Definition: acme_client.h:295
@ ACME_REQ_STATE_RECEIVE_BODY
Definition: acme_client.h:296
@ ERROR_INVALID_RESPONSE
Definition: error.h:71
ACME client (Automatic Certificate Management Environment)
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.