acme_client_challenge.c
Go to the documentation of this file.
1 /**
2  * @file acme_client_challenge.c
3  * @brief Challenge object 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"
37 #include "acme/acme_client_jose.h"
38 #include "acme/acme_client_misc.h"
39 #include "pkix/pem_export.h"
40 #include "pkix/x509_cert_create.h"
41 #include "encoding/base64url.h"
42 #include "encoding/asn1.h"
43 #include "jansson.h"
44 #include "debug.h"
45 
46 //Check TCP/IP stack configuration
47 #if (ACME_CLIENT_SUPPORT == ENABLED)
48 
49 //id-pe-acmeIdentifier OID (1.3.6.1.5.5.7.1.31)
50 const uint8_t ACME_IDENTIFIER_OID[8] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x1F};
51 
52 
53 /**
54  * @brief Send HTTP request (challenge URL)
55  * @param[in] context Pointer to the ACME client context
56  * @param[in] challenge Pointer to the challenge object
57  * @return Error code
58  **/
59 
61  AcmeChallenge *challenge)
62 {
63  error_t error;
64 
65  //Initialize variables
66  error = NO_ERROR;
67 
68  //Perform HTTP request
69  while(!error)
70  {
71  //Check HTTP request state
72  if(context->requestState == ACME_REQ_STATE_INIT)
73  {
74  //Debug message
75  TRACE_DEBUG("\r\n");
76  TRACE_DEBUG("###############################################################################\r\n");
77  TRACE_DEBUG("## CHALLENGE READY ############################################################\r\n");
78  TRACE_DEBUG("###############################################################################\r\n");
79  TRACE_DEBUG("\r\n");
80 
81  //Update HTTP request state
82  context->requestState = ACME_REQ_STATE_FORMAT_BODY;
83  }
84  else if(context->requestState == ACME_REQ_STATE_FORMAT_BODY)
85  {
86  //Format the body of the HTTP request
87  error = acmeClientFormatChallengeReadyRequest(context, challenge);
88 
89  //Check status code
90  if(!error)
91  {
92  //Update HTTP request state
93  context->requestState = ACME_REQ_STATE_FORMAT_HEADER;
94  }
95  }
96  else if(context->requestState == ACME_REQ_STATE_FORMAT_HEADER)
97  {
98  //The client indicates to the server that it is ready for the challenge
99  //validation by sending an empty JSON body carried in a POST request to
100  //the challenge URL (refer to RFC 8555, section 7.5.1)
101  error = acmeClientFormatRequestHeader(context, "POST", challenge->url);
102 
103  //Check status code
104  if(!error)
105  {
106  //Update HTTP request state
107  context->requestState = ACME_REQ_STATE_SEND_HEADER;
108  }
109  }
110  else if(context->requestState == ACME_REQ_STATE_SEND_HEADER ||
111  context->requestState == ACME_REQ_STATE_SEND_BODY ||
112  context->requestState == ACME_REQ_STATE_RECEIVE_HEADER ||
113  context->requestState == ACME_REQ_STATE_PARSE_HEADER ||
114  context->requestState == ACME_REQ_STATE_RECEIVE_BODY ||
115  context->requestState == ACME_REQ_STATE_CLOSE_BODY)
116  {
117  //Perform HTTP request/response transaction
118  error = acmeClientSendRequest(context);
119  }
120  else if(context->requestState == ACME_REQ_STATE_PARSE_BODY)
121  {
122  //Parse the body of the HTTP response
123  error = acmeClientParseChallengeReadyResponse(context);
124 
125  //The HTTP transaction is complete
126  context->requestState = ACME_REQ_STATE_INIT;
127  break;
128  }
129  else
130  {
131  //Invalid state
132  error = ERROR_WRONG_STATE;
133  }
134  }
135 
136  //Return status code
137  return error;
138 }
139 
140 
141 /**
142  * @brief Format HTTP request body (challenge URL)
143  * @param[in] context Pointer to the ACME client context
144  * @param[in] challenge Pointer to the challenge object
145  * @return Error code
146  **/
147 
149  AcmeChallenge *challenge)
150 {
151  error_t error;
152  size_t n;
153  char_t *protected;
154  const char_t *payload;
155 
156  //The client must send an empty JSON body (refer to RFC 8555, section 7.5.1)
157  payload = "{}";
158 
159  //Point to the buffer where to format the JWS protected header
160  protected = context->buffer;
161 
162  //Format JWS protected header
163  error = acmeClientFormatJwsProtectedHeader(&context->accountKey,
164  context->account.url, context->nonce, challenge->url,
165  protected, &n);
166 
167  //Check status code
168  if(!error)
169  {
170  //Generate the JSON Web Signature
171  error = jwsCreate(context->prngAlgo, context->prngContext, protected,
172  payload, context->accountKey.alg, context->accountKey.crv,
173  context->accountKey.privateKey, context->buffer, &context->bufferLen);
174  }
175 
176  //Return status code
177  return error;
178 }
179 
180 
181 /**
182  * @brief Parse HTTP response (challenge URL)
183  * @param[in] context Pointer to the ACME client context
184  * @return Error code
185  **/
186 
188 {
189  //Check HTTP status code
190  if(!HTTP_STATUS_CODE_2YZ(context->statusCode))
192 
193  //The server must include a Replay-Nonce header field in every successful
194  //response to a POST request (refer to RFC 8555, section 6.5)
195  if(context->nonce[0] == '\0')
196  return ERROR_INVALID_RESPONSE;
197 
198  //The response to a HEAD request does not contain a body
199  return NO_ERROR;
200 }
201 
202 
203 /**
204  * @brief Parse challenge status field
205  * @param[in] label Textual representation of the status
206  * @return Authorization status code
207  **/
208 
210 {
211  AcmeChallengeStatus status;
212 
213  //Check the status of the challenge (refer to RFC 8555, section 7.1.6)
214  if(osStrcmp(label, "pending") == 0)
215  {
216  //Challenge objects are created in the "pending" state
218  }
219  else if(osStrcmp(label, "processing") == 0)
220  {
221  //They transition to the "processing" state when the client responds to
222  //the challenge
224  }
225  else if(osStrcmp(label, "valid") == 0)
226  {
227  //If validation is successful, the challenge moves to the "valid" state
229  }
230  else if(osStrcmp(label, "invalid") == 0)
231  {
232  //If there is an error, the challenge moves to the "invalid" state
234  }
235  else
236  {
237  //Unknown status
239  }
240 
241  //Return current status
242  return status;
243 }
244 
245 
246 /**
247  * @brief Parse challenge type field
248  * @param[in] label Textual representation of the challenge type
249  * @return Challenge type
250  **/
251 
253 {
255 
256  //Check challenge type
257  if(osStrcmp(label, "http-01") == 0)
258  {
259  //HTTP challenge
261  }
262  else if(osStrcmp(label, "dns-01") == 0)
263  {
264  //DNS challenge
266  }
267  else if(osStrcmp(label, "tls-alpn-01") == 0)
268  {
269  //TLS ALPN challenge
271  }
272  else
273  {
274  //Unknown challenge
276  }
277 
278  //Return challenge type
279  return type;
280 }
281 
282 
283 /**
284  * @brief Retrieve the challenge type used for a given domain name
285  * @param[in] context Pointer to the ACME client context
286  * @param[in] identifier NULL-terminated string that contains a domain name
287  * @param[in] wildcard Wildcard domain name
288  * @return Challenge type
289  **/
290 
292  const char_t *identifier, bool_t wildcard)
293 {
294  uint_t i;
296 
297  //Initialize challenge type
299 
300  //Loop through the list of identifiers
301  for(i = 0; i < context->numIdentifiers; i++)
302  {
303  //Any identifier of type "dns" may have a wildcard domain name
304  //as its value
305  if(wildcard)
306  {
307  //A wildcard domain name consists of a single asterisk character
308  //followed by a single full stop character ("*.") followed by a
309  //domain name
310  if(osStrncmp(context->identifiers[i].value, "*.", 2) == 0 &&
311  osStrcmp(context->identifiers[i].value + 2, identifier) == 0)
312  {
313  type = context->identifiers[i].challengeType;
314  break;
315  }
316  }
317  else
318  {
319  //Compare identifier values
320  if(osStrcmp(context->identifiers[i].value, identifier) == 0)
321  {
322  type = context->identifiers[i].challengeType;
323  break;
324  }
325  }
326  }
327 
328  //Return challenge type
329  return type;
330 }
331 
332 
333 /**
334  * @brief Generate key authorization
335  * @param[in] context Pointer to the ACME client context
336  * @param[in] challenge Pointer to the challenge object
337  * @return Error code
338  **/
339 
341  AcmeChallenge *challenge)
342 {
343  error_t error;
344  size_t n;
345  char_t *p;
346  uint8_t digest[SHA256_DIGEST_SIZE];
347 
348  //Point to the buffer where to format the key authorization
349  p = challenge->keyAuth;
350 
351  //A key authorization is a string that concatenates the token for the
352  //challenge with a key fingerprint, separated by a "." character
353  osStrcpy(p, challenge->token);
354  osStrcat(p, ".");
355 
356  //Point to the buffer where to format the JWK thumbprint
357  p += osStrlen(challenge->token) + 1;
358 
359  //Construct a JSON object containing only the required members of a JWK
360  //representing the key and with no whitespace or line breaks before or
361  //after any syntactic elements and with the required members ordered
362  //lexicographically (refer to RFC 7638, section 3)
363  error = acmeClientFormatJwk(&context->accountKey, context->buffer, &n, TRUE);
364 
365  //Check status code
366  if(!error)
367  {
368  //Hash the octets of the UTF-8 representation of this JSON object using
369  //SHA-256 (refer to RFC 8555, section 8.1)
370  error = sha256Compute(context->buffer, n, digest);
371  }
372 
373  //Check status code
374  if(!error)
375  {
376  //Encode the resulting JWK thumbprint using Base64url
377  base64urlEncode(digest, sizeof(digest), p, &n);
378  }
379 
380  //Return status code
381  return error;
382 }
383 
384 
385 /**
386  * @brief Digest the key authorization (for DNS challenge only)
387  * @param[in] context Pointer to the ACME client context
388  * @param[in] challenge Pointer to the challenge object
389  * @return Error code
390  **/
391 
393  AcmeChallenge *challenge)
394 {
395 #if (ACME_CLIENT_DNS_CHALLENGE_SUPPORT == ENABLED)
396  error_t error;
397 
398  //The client computes the SHA-256 digest of the key authorization
399  error = sha256Compute(challenge->keyAuth, osStrlen(challenge->keyAuth),
400  (uint8_t *) context->buffer);
401 
402  //Check status code
403  if(!error)
404  {
405  //Encode the digest using Base64url
406  base64urlEncode(context->buffer, SHA256_DIGEST_SIZE, challenge->keyAuth,
407  NULL);
408  }
409 
410  //Return status code
411  return error;
412 #else
413  //DNS challenge is not implemented
414  return ERROR_NOT_IMPLEMENTED;
415 #endif
416 }
417 
418 
419 /**
420  * @brief Generate a self-signed certificate (TLS-ALPN challenge only)
421  * @param[in] context Pointer to the ACME client context
422  * @param[in] challenge Pointer to the challenge object
423  * @return Error code
424  **/
425 
427  AcmeChallenge *challenge)
428 {
429 #if (ACME_CLIENT_TLS_ALPN_CHALLENGE_SUPPORT == ENABLED)
430  error_t error;
431  size_t n;
432  X509CertRequestInfo *certReqInfo;
434  X509Validity validity;
435  X509SignAlgoId signatureAlgo;
436  uint8_t digest[SHA256_DIGEST_SIZE + 2];
437 
438  //Allocate a memory buffer to hold the certificate request information
439  certReqInfo = cryptoAllocMem(sizeof(X509CertRequestInfo));
440 
441  //Successful memory allocation?
442  if(certReqInfo != NULL)
443  {
444  //Clear certificate request information
445  osMemset(certReqInfo, 0, sizeof(X509CertRequestInfo));
446 
447  //The client prepares for validation by constructing a self-signed
448  //certificate that must contain an acmeIdentifier extension and a
449  //subjectAlternativeName extension
450  certReqInfo->subject.commonName.value = challenge->identifier;
451  certReqInfo->subject.commonName.length = osStrlen(challenge->identifier);
452 
453  //Point to the certificate extensions
454  extensions = &certReqInfo->attributes.extensionReq;
455 
456  //Set the basicConstraints extension
457  extensions->basicConstraints.critical = TRUE;
458  extensions->basicConstraints.cA = TRUE;
459  extensions->basicConstraints.pathLenConstraint = -1;
460 
461  //The subjectAlternativeName extension must contain a single DNS name entry
462  //where the value is the domain name being validated
463  extensions->subjectAltName.numGeneralNames = 1;
464  extensions->subjectAltName.generalNames[0].type = X509_GENERAL_NAME_TYPE_DNS;
465  extensions->subjectAltName.generalNames[0].value = challenge->identifier;
466  extensions->subjectAltName.generalNames[0].length = osStrlen(challenge->identifier);
467 
468  //The acmeIdentifier extension must contain the SHA-256 digest of the key
469  //authorization for the challenge
470  digest[0] = ASN1_TYPE_OCTET_STRING;
471  digest[1] = SHA256_DIGEST_SIZE;
472 
473  //Compute the SHA-256 digest of the key authorization
474  error = sha256Compute(challenge->keyAuth, osStrlen(challenge->keyAuth),
475  digest + 2);
476 
477  //Check status code
478  if(!error)
479  {
480  //The acmeIdentifier extension must be critical so that the certificate
481  //cannot be inadvertently used by non-ACME software
482  extensions->numCustomExtensions = 1;
483  extensions->customExtensions[0].oid.value = ACME_IDENTIFIER_OID;
484  extensions->customExtensions[0].oid.length = sizeof(ACME_IDENTIFIER_OID);
485  extensions->customExtensions[0].critical = TRUE;
486  extensions->customExtensions[0].data.value = digest;
487  extensions->customExtensions[0].data.length = sizeof(digest);
488 
489 #if (ACME_CLIENT_RSA_SUPPORT == ENABLED)
490  //RSA key pair?
491  if(context->certKey.type == X509_KEY_TYPE_RSA)
492  {
493  //Set public key identifier
495  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(RSA_ENCRYPTION_OID);
496 
497  //Select the signature algorithm
498  signatureAlgo.oid.value = SHA256_WITH_RSA_ENCRYPTION_OID;
499  signatureAlgo.oid.length = sizeof(SHA256_WITH_RSA_ENCRYPTION_OID);
500  }
501  else
502 #endif
503 #if (ACME_CLIENT_ECDSA_SUPPORT == ENABLED)
504  //EC key pair?
505  if(context->certKey.type == X509_KEY_TYPE_EC)
506  {
507  X509EcParameters *ecParams;
508 
509  //Set public key identifier
511  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(EC_PUBLIC_KEY_OID);
512 
513  //Point to the EC domain parameters
514  ecParams = &certReqInfo->subjectPublicKeyInfo.ecParams;
515 
516  //Select the relevant elliptic curve
517  if(osStrcmp(context->certKey.ecParams.name, "secp256r1") == 0)
518  {
519  ecParams->namedCurve.value = SECP256R1_OID;
520  ecParams->namedCurve.length = sizeof(SECP256R1_OID);
521  }
522  else if(osStrcmp(context->certKey.ecParams.name, "secp384r1") == 0)
523  {
524  ecParams->namedCurve.value = SECP384R1_OID;
525  ecParams->namedCurve.length = sizeof(SECP384R1_OID);
526  }
527  else if(osStrcmp(context->certKey.ecParams.name, "secp521r1") == 0)
528  {
529  ecParams->namedCurve.value = SECP521R1_OID;
530  ecParams->namedCurve.length = sizeof(SECP521R1_OID);
531  }
532  else
533  {
534  //Report an error
535  error = ERROR_INVALID_KEY;
536  }
537 
538  //Select the signature algorithm
539  signatureAlgo.oid.value = ECDSA_WITH_SHA256_OID;
540  signatureAlgo.oid.length = sizeof(ECDSA_WITH_SHA256_OID);
541  }
542  else
543 #endif
544 #if (ACME_CLIENT_ED25519_SUPPORT == ENABLED)
545  //Ed25519 key pair?
546  if(context->certKey.type == X509_KEY_TYPE_ED25519)
547  {
548  //Set public key identifier
549  certReqInfo->subjectPublicKeyInfo.oid.value = ED25519_OID;
550  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(ED25519_OID);
551 
552  //Select the signature algorithm
553  signatureAlgo.oid.value = ED25519_OID;
554  signatureAlgo.oid.length = sizeof(ED25519_OID);
555  }
556  else
557 #endif
558 #if (ACME_CLIENT_ED448_SUPPORT == ENABLED)
559  //Ed448 key pair?
560  if(context->certKey.type == X509_KEY_TYPE_ED448)
561  {
562  //Set public key identifier
563  certReqInfo->subjectPublicKeyInfo.oid.value = ED448_OID;
564  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(ED448_OID);
565 
566  //Select the signature algorithm
567  signatureAlgo.oid.value = ED448_OID;
568  signatureAlgo.oid.length = sizeof(ED448_OID);
569  }
570  else
571 #endif
572  //Invalid key pair?
573  {
574  //Report an error
575  error = ERROR_INVALID_KEY;
576  }
577  }
578 
579  //Check status code
580  if(!error)
581  {
582  //Validity period
583  validity.notBefore.year = 2018;
584  validity.notBefore.month = 1;
585  validity.notBefore.day = 1;
586  validity.notBefore.hours = 12;
587  validity.notBefore.minutes = 0;
588  validity.notBefore.seconds = 0;
589  validity.notAfter.year = 2019;
590  validity.notAfter.month = 1;
591  validity.notAfter.day = 1;
592  validity.notAfter.hours = 12;
593  validity.notAfter.minutes = 0;
594  validity.notAfter.seconds = 0;
595 
596  //Create a self-signed certificate
597  error = x509CreateCertificate(context->prngAlgo, context->prngContext,
598  certReqInfo, context->certKey.publicKey, NULL, NULL,
599  &validity, &signatureAlgo, context->certKey.privateKey,
600  (uint8_t *) context->buffer, &n);
601  }
602 
603  //Check status code
604  if(!error)
605  {
606  //Export the certificate to PEM format
607  error = pemExportCertificate((uint8_t *) context->buffer, n,
608  challenge->cert, &n);
609  }
610 
611  //Release previously allocated memory
612  cryptoFreeMem(certReqInfo);
613  }
614  else
615  {
616  //Failed to allocate memory
617  error = ERROR_OUT_OF_MEMORY;
618  }
619 
620  //Return status code
621  return error;
622 #else
623  //TLS-ALPN challenge is not implemented
624  return ERROR_NOT_IMPLEMENTED;
625 #endif
626 }
627 
628 #endif
@ X509_KEY_TYPE_RSA
Definition: x509_common.h:587
AcmeChallengeType acmeClientParseChallengeType(const char_t *label)
Parse challenge type field.
uint8_t extensions[]
Definition: ntp_common.h:207
int bool_t
Definition: compiler_port.h:53
@ ACME_CHALLENGE_STATUS_PENDING
Definition: acme_client.h:353
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
#define HTTP_STATUS_CODE_2YZ(code)
Definition: http_common.h:44
uint8_t p
Definition: ndp.h:300
Validity.
Definition: x509_common.h:715
@ ACME_CHALLENGE_STATUS_INVALID
Definition: acme_client.h:356
X509OctetString oid
Definition: x509_common.h:792
uint16_t year
Definition: date_time.h:48
#define TRUE
Definition: os_port.h:50
Helper functions for ACME client.
const uint8_t EC_PUBLIC_KEY_OID[7]
Definition: ec.c:43
X509EcParameters ecParams
Definition: x509_common.h:802
@ ACME_REQ_STATE_PARSE_BODY
Definition: acme_client.h:297
Challenge object.
Definition: acme_client.h:547
uint8_t type
Definition: coap_common.h:176
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
X509Extensions extensionReq
Definition: x509_common.h:1250
@ ACME_CHALLENGE_TYPE_DNS_01
Definition: acme_client.h:368
#define osStrcmp(s1, s2)
Definition: os_port.h:171
AcmeChallengeType acmeClientGetChallengeType(AcmeClientContext *context, const char_t *identifier, bool_t wildcard)
Retrieve the challenge type used for a given domain name.
#define osStrlen(s)
Definition: os_port.h:165
const uint8_t ECDSA_WITH_SHA256_OID[8]
Definition: ecdsa.c:49
JOSE (JSON Object Signing and Encryption)
size_t length
Definition: x509_common.h:644
Challenge object management.
const uint8_t SECP256R1_OID[8]
Definition: ec_curves.c:72
X509String commonName
Definition: x509_common.h:677
error_t acmeClientParseChallengeReadyResponse(AcmeClientContext *context)
Parse HTTP response (challenge URL)
@ ERROR_WRONG_STATE
Definition: error.h:209
uint8_t day
Definition: date_time.h:50
@ ACME_REQ_STATE_FORMAT_HEADER
Definition: acme_client.h:290
error_t acmeClientSendRequest(AcmeClientContext *context)
Send HTTP request.
const uint8_t SECP521R1_OID[5]
Definition: ec_curves.c:76
AcmeChallengeStatus acmeClientParseChallengeStatus(const char_t *label)
Parse challenge status field.
@ X509_KEY_TYPE_EC
Definition: x509_common.h:590
X509SubjectPublicKeyInfo subjectPublicKeyInfo
Definition: x509_common.h:1263
@ ACME_CHALLENGE_STATUS_PROCESSING
Definition: acme_client.h:354
DateTime notAfter
Definition: x509_common.h:717
error_t acmeClientFormatChallengeReadyRequest(AcmeClientContext *context, AcmeChallenge *challenge)
Format HTTP request body (challenge URL)
@ ERROR_UNEXPECTED_STATUS
Definition: error.h:283
X.509 certificate generation.
@ X509_GENERAL_NAME_TYPE_DNS
Definition: x509_common.h:521
error_t acmeClientFormatRequestHeader(AcmeClientContext *context, const char_t *method, const char_t *url)
Format HTTP request header.
uint8_t minutes
Definition: date_time.h:53
error_t
Error codes.
Definition: error.h:43
EC parameters.
Definition: x509_common.h:770
void base64urlEncode(const void *input, size_t inputLen, char_t *output, size_t *outputLen)
Base64url encoding algorithm.
Definition: base64url.c:72
error_t x509CreateCertificate(const PrngAlgo *prngAlgo, void *prngContext, const X509CertRequestInfo *certReqInfo, const void *subjectPublicKey, const X509CertInfo *issuerCertInfo, const X509SerialNumber *serialNumber, const X509Validity *validity, const X509SignAlgoId *signatureAlgo, const void *signerPrivateKey, uint8_t *output, size_t *written)
Generate a X.509 certificate.
error_t acmeClientFormatJwsProtectedHeader(const AcmeKeyPair *keyPair, const char_t *kid, const char_t *nonce, const char_t *url, char_t *buffer, size_t *written)
Format JWS protected header.
@ ACME_CHALLENGE_TYPE_HTTP_01
Definition: acme_client.h:367
AcmeChallengeStatus
Challenge status.
Definition: acme_client.h:351
@ ACME_REQ_STATE_CLOSE_BODY
Definition: acme_client.h:298
error_t acmeClientDigestKeyAuthorization(AcmeClientContext *context, AcmeChallenge *challenge)
Digest the key authorization (for DNS challenge only)
error_t acmeClientGenerateKeyAuthorization(AcmeClientContext *context, AcmeChallenge *challenge)
Generate key authorization.
error_t acmeClientGenerateTlsAlpnCert(AcmeClientContext *context, AcmeChallenge *challenge)
Generate a self-signed certificate (TLS-ALPN challenge only)
Base64url encoding scheme.
@ ACME_CHALLENGE_TYPE_NONE
Definition: acme_client.h:366
@ ACME_REQ_STATE_INIT
Definition: acme_client.h:289
uint8_t hours
Definition: date_time.h:52
error_t acmeClientFormatJwk(const AcmeKeyPair *keyPair, char_t *buffer, size_t *written, bool_t sort)
Export a public key to JWK format.
X509OctetString oid
Definition: x509_common.h:1041
CertificationRequestInfo structure.
Definition: x509_common.h:1259
char_t identifier[ACME_CLIENT_MAX_NAME_LEN+1]
Domain name.
Definition: acme_client.h:550
char_t url[ACME_CLIENT_MAX_URL_LEN+1]
Challenge URL.
Definition: acme_client.h:552
uint8_t seconds
Definition: date_time.h:54
const uint8_t SHA256_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:68
@ ACME_REQ_STATE_FORMAT_BODY
Definition: acme_client.h:292
X509OctetString namedCurve
Definition: x509_common.h:771
const uint8_t ACME_IDENTIFIER_OID[8]
const uint8_t ED448_OID[3]
Definition: ec_curves.c:102
const uint8_t SECP384R1_OID[5]
Definition: ec_curves.c:74
@ ACME_REQ_STATE_RECEIVE_HEADER
Definition: acme_client.h:294
PEM file export functions.
const uint8_t ED25519_OID[3]
Definition: ec_curves.c:100
const uint8_t RSA_ENCRYPTION_OID[9]
Definition: rsa.c:57
@ ASN1_TYPE_OCTET_STRING
Definition: asn1.h:72
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint8_t month
Definition: date_time.h:49
char char_t
Definition: compiler_port.h:48
#define osStrcat(s1, s2)
Definition: os_port.h:219
#define AcmeClientContext
Definition: acme_client.h:248
AcmeChallengeType
Challenge types.
Definition: acme_client.h:365
DateTime notBefore
Definition: x509_common.h:716
const char_t * value
Definition: x509_common.h:643
@ X509_KEY_TYPE_ED448
Definition: x509_common.h:595
error_t jwsCreate(const PrngAlgo *prngAlgo, void *prngContext, const char_t *protected, const char_t *payload, const char_t *alg, const char_t *crv, const void *privateKey, char_t *buffer, size_t *written)
Create a JSON Web Signature.
uint8_t n
char_t keyAuth[ACME_CLIENT_MAX_KEY_AUTH_LEN+1]
Key authorization.
Definition: acme_client.h:554
error_t pemExportCertificate(const uint8_t *cert, size_t certLen, char_t *output, size_t *written)
Export an X.509 certificate to PEM format.
Definition: pem_export.c:57
uint8_t payload[]
Definition: ipv6.h:286
@ ACME_CHALLENGE_TYPE_TLS_ALPN_01
Definition: acme_client.h:369
#define cryptoFreeMem(p)
Definition: crypto.h:791
error_t sha256Compute(const void *data, size_t length, uint8_t *digest)
Digest a message using SHA-256.
@ ACME_REQ_STATE_SEND_HEADER
Definition: acme_client.h:291
uint8_t identifier[]
#define cryptoAllocMem(size)
Definition: crypto.h:786
@ ACME_REQ_STATE_PARSE_HEADER
Definition: acme_client.h:295
X.509 certificate extensions.
Definition: x509_common.h:1003
@ ACME_CHALLENGE_STATUS_VALID
Definition: acme_client.h:355
#define osStrncmp(s1, s2, length)
Definition: os_port.h:177
const uint8_t * value
Definition: x509_common.h:654
@ ACME_REQ_STATE_RECEIVE_BODY
Definition: acme_client.h:296
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
@ X509_KEY_TYPE_ED25519
Definition: x509_common.h:593
@ ACME_REQ_STATE_SEND_BODY
Definition: acme_client.h:293
#define SHA256_DIGEST_SIZE
Definition: sha256.h:45
char_t cert[ACME_CLIENT_MAX_TLS_ALPN_CERT_LEN+1]
TLS-ALPN certificate.
Definition: acme_client.h:556
X509Attributes attributes
Definition: x509_common.h:1264
#define osStrcpy(s1, s2)
Definition: os_port.h:207
@ ERROR_INVALID_RESPONSE
Definition: error.h:71
ACME client (Automatic Certificate Management Environment)
error_t acmeClientSendChallengeReadyRequest(AcmeClientContext *context, AcmeChallenge *challenge)
Send HTTP request (challenge URL)
Signature algorithm identifier.
Definition: x509_common.h:1040
@ ERROR_INVALID_KEY
Definition: error.h:106
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
ASN.1 (Abstract Syntax Notation One)
char_t token[ACME_CLIENT_MAX_TOKEN_LEN+1]
Token value.
Definition: acme_client.h:553