acme_client_misc.c
Go to the documentation of this file.
1 /**
2  * @file acme_client_misc.c
3  * @brief Helper functions for ACME client
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2025 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.5.0
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_jose.h"
37 #include "acme/acme_client_misc.h"
38 #include "pkix/pem_import.h"
40 #include "pkix/x509_csr_create.h"
41 #include "encoding/base64url.h"
42 #include "encoding/oid.h"
43 #include "jansson.h"
44 #include "jansson_private.h"
45 #include "debug.h"
46 
47 //Check TCP/IP stack configuration
48 #if (ACME_CLIENT_SUPPORT == ENABLED)
49 
50 
51 /**
52  * @brief Load public/private key pair
53  * @param[in] keyPair Pointer to the key pair
54  * @param[in] publicKey Public key (PEM format)
55  * @param[in] publicKeyLen Length of the public key
56  * @param[in] privateKey Private key (PEM format)
57  * @param[in] privateKeyLen Length of the private key
58  * @param[in] password NULL-terminated string containing the password. This
59  * parameter is required if the private key is encrypted
60  * @return Error code
61  **/
62 
63 error_t acmeClientLoadKeyPair(AcmeKeyPair *keyPair, const char_t *publicKey,
64  size_t publicKeyLen, const char_t *privateKey, size_t privateKeyLen,
65  const char_t *password)
66 {
67  error_t error;
69 
70  //Clear key pair
71  osMemset(keyPair, 0, sizeof(AcmeKeyPair));
72 
73  //Extract the type of the public key
74  type = pemGetPublicKeyType(publicKey, publicKeyLen);
75 
76 #if (ACME_CLIENT_RSA_SUPPORT == ENABLED)
77  //RSA public key?
78  if(type == X509_KEY_TYPE_RSA)
79  {
80  //Save public key type
81  keyPair->type = X509_KEY_TYPE_RSA;
82 
83  //Initialize RSA public and private keys
84  rsaInitPublicKey(&keyPair->rsaPublicKey);
86 
87  //Decode the PEM file that contains the RSA public key
88  error = pemImportRsaPublicKey(&keyPair->rsaPublicKey, publicKey,
89  publicKeyLen);
90 
91  //Check status code
92  if(!error)
93  {
94  //Decode the PEM file that contains the RSA private key
95  error = pemImportRsaPrivateKey(&keyPair->rsaPrivateKey, privateKey,
96  privateKeyLen, password);
97  }
98 
99  //Check status code
100  if(!error)
101  {
102  //Select RSA keys
103  keyPair->publicKey = &keyPair->rsaPublicKey;
104  keyPair->privateKey = &keyPair->rsaPrivateKey;
105 
106  //Select the relevant signature algorithm
107  osStrcpy(keyPair->alg, "RS256");
108  }
109  }
110  else
111 #endif
112 #if (ACME_CLIENT_ECDSA_SUPPORT == ENABLED)
113  //EC public key?
114  if(type == X509_KEY_TYPE_EC)
115  {
116  //Save public key type
117  keyPair->type = X509_KEY_TYPE_EC;
118 
119  //Initialize EC public and private keys
120  ecInitPublicKey(&keyPair->ecPublicKey);
121  ecInitPrivateKey(&keyPair->ecPrivateKey);
122 
123  //Decode the PEM file that contains the EC public key
124  error = pemImportEcPublicKey(&keyPair->ecPublicKey, publicKey,
125  publicKeyLen);
126 
127  //Check status code
128  if(!error)
129  {
130  //Decode the PEM file that contains the EC private key
131  error = pemImportEcPrivateKey(&keyPair->ecPrivateKey, privateKey,
132  privateKeyLen, password);
133  }
134 
135  //Check status code
136  if(!error)
137  {
138  //Select EC keys
139  keyPair->publicKey = &keyPair->ecPublicKey;
140  keyPair->privateKey = &keyPair->ecPrivateKey;
141 
142  //Select the relevant signature algorithm
143  if(osStrcmp(keyPair->ecPublicKey.curve->name, "secp256r1") == 0 &&
144  osStrcmp(keyPair->ecPrivateKey.curve->name, "secp256r1") == 0)
145  {
146  //ECDSA using P-256 and SHA-256
147  osStrcpy(keyPair->alg, "ES256");
148  }
149  else if(osStrcmp(keyPair->ecPublicKey.curve->name, "secp384r1") == 0 &&
150  osStrcmp(keyPair->ecPrivateKey.curve->name, "secp384r1") == 0)
151  {
152  //ECDSA using P-384 and SHA-384
153  osStrcpy(keyPair->alg, "ES384");
154  }
155  else if(osStrcmp(keyPair->ecPublicKey.curve->name, "secp521r1") == 0 &&
156  osStrcmp(keyPair->ecPrivateKey.curve->name, "secp521r1") == 0)
157  {
158  //ECDSA using P-521 and SHA-512
159  osStrcpy(keyPair->alg, "ES512");
160  }
161  else
162  {
163  //Report an error
164  error = ERROR_INVALID_KEY;
165  }
166  }
167  }
168  else
169 #endif
170 #if (ACME_CLIENT_ED25519_SUPPORT == ENABLED)
171  //Ed22519 public key?
173  {
174  //Save public key type
175  keyPair->type = X509_KEY_TYPE_ED25519;
176 
177  //Initialize EdDSA public and private keys
180 
181  //Decode the PEM file that contains the EdDSA public key
182  error = pemImportEddsaPublicKey(&keyPair->eddsaPublicKey, publicKey,
183  publicKeyLen);
184 
185  //Check status code
186  if(!error)
187  {
188  //Decode the PEM file that contains the EdDSA private key
189  error = pemImportEddsaPrivateKey(&keyPair->eddsaPrivateKey,
190  privateKey, privateKeyLen, password);
191  }
192 
193  //Check status code
194  if(!error)
195  {
196  //Valid Ed25519 key pair?
197  if(keyPair->eddsaPublicKey.curve == ED25519_CURVE &&
198  keyPair->eddsaPrivateKey.curve == ED25519_CURVE)
199  {
200  //Select EdDSA keys
201  keyPair->publicKey = &keyPair->eddsaPublicKey;
202  keyPair->privateKey = &keyPair->eddsaPrivateKey;
203 
204  //Select the relevant signature algorithm
205  osStrcpy(keyPair->alg, "EdDSA");
206  }
207  else
208  {
209  //Report an error
210  error = ERROR_INVALID_KEY;
211  }
212  }
213  }
214  else
215 #endif
216 #if (ACME_CLIENT_ED448_SUPPORT == ENABLED)
217  //Ed448 public key?
219  {
220  //Save public key type
221  keyPair->type = X509_KEY_TYPE_ED448;
222 
223  //Initialize EdDSA public and private keys
226 
227  //Decode the PEM file that contains the EdDSA public key
228  error = pemImportEddsaPublicKey(&keyPair->eddsaPublicKey, publicKey,
229  publicKeyLen);
230 
231  //Check status code
232  if(!error)
233  {
234  //Decode the PEM file that contains the EdDSA private key
235  error = pemImportEddsaPrivateKey(&keyPair->eddsaPrivateKey,
236  privateKey, privateKeyLen, password);
237  }
238 
239  //Check status code
240  if(!error)
241  {
242  //Valid Ed448 key pair?
243  if(keyPair->eddsaPublicKey.curve == ED448_CURVE &&
244  keyPair->eddsaPrivateKey.curve == ED448_CURVE)
245  {
246  //Select EdDSA keys
247  keyPair->publicKey = &keyPair->eddsaPublicKey;
248  keyPair->privateKey = &keyPair->eddsaPrivateKey;
249 
250  //Select the relevant signature algorithm
251  osStrcpy(keyPair->alg, "EdDSA");
252  }
253  else
254  {
255  //Report an error
256  error = ERROR_INVALID_KEY;
257  }
258  }
259  }
260  else
261 #endif
262  //Invalid public key?
263  {
264  //The supplied public key is not valid
265  error = ERROR_INVALID_KEY;
266  }
267 
268  //Any error to report?
269  if(error)
270  {
271  //Clean up side effects
272  acmeClientUnloadKeyPair(keyPair);
273  }
274 
275  //Return status code
276  return error;
277 }
278 
279 
280 /**
281  * @brief Load certificate/private key pair
282  * @param[in] keyPair Pointer to the key pair
283  * @param[in] cert Certificate (PEM format)
284  * @param[in] certLen Length of the certificate
285  * @param[in] privateKey Private key (PEM format)
286  * @param[in] privateKeyLen Length of the private key
287  * @param[in] password NULL-terminated string containing the password. This
288  * parameter is required if the private key is encrypted
289  * @return Error code
290  **/
291 
293  size_t certLen, const char_t *privateKey, size_t privateKeyLen,
294  const char_t *password)
295 {
296  error_t error;
298 
299  //Clear key pair
300  osMemset(keyPair, 0, sizeof(AcmeKeyPair));
301 
302  //Extract the type of the public key contained in the certificate
303  type = pemGetCertPublicKeyType(cert, certLen);
304 
305 #if (ACME_CLIENT_RSA_SUPPORT == ENABLED)
306  //RSA public key?
307  if(type == X509_KEY_TYPE_RSA)
308  {
309  //Save public key type
310  keyPair->type = X509_KEY_TYPE_RSA;
311 
312  //Initialize RSA public and private keys
313  rsaInitPublicKey(&keyPair->rsaPublicKey);
314  rsaInitPrivateKey(&keyPair->rsaPrivateKey);
315 
316  //Extract the RSA public key from the certificate
317  error = pemImportRsaCertPublicKey(&keyPair->rsaPublicKey, cert, certLen);
318 
319  //Check status code
320  if(!error)
321  {
322  //Decode the PEM file that contains the RSA private key
323  error = pemImportRsaPrivateKey(&keyPair->rsaPrivateKey, privateKey,
324  privateKeyLen, password);
325  }
326 
327  //Check status code
328  if(!error)
329  {
330  //Select RSA keys
331  keyPair->publicKey = &keyPair->rsaPublicKey;
332  keyPair->privateKey = &keyPair->rsaPrivateKey;
333 
334  //Select the relevant signature algorithm
335  osStrcpy(keyPair->alg, "RS256");
336  }
337  }
338  else
339 #endif
340 #if (ACME_CLIENT_ECDSA_SUPPORT == ENABLED)
341  //EC public key?
342  if(type == X509_KEY_TYPE_EC)
343  {
344  //Save public key type
345  keyPair->type = X509_KEY_TYPE_EC;
346 
347  //Initialize EC public and private keys
348  ecInitPublicKey(&keyPair->ecPublicKey);
349  ecInitPrivateKey(&keyPair->ecPrivateKey);
350 
351  //Extract the EC public key from the certificate
352  error = pemImportEcCertPublicKey(&keyPair->ecPublicKey, cert, certLen);
353 
354  //Check status code
355  if(!error)
356  {
357  //Decode the PEM file that contains the EC private key
358  error = pemImportEcPrivateKey(&keyPair->ecPrivateKey, privateKey,
359  privateKeyLen, password);
360  }
361 
362  //Check status code
363  if(!error)
364  {
365  //Select EC keys
366  keyPair->publicKey = &keyPair->ecPublicKey;
367  keyPair->privateKey = &keyPair->ecPrivateKey;
368 
369  //Select the relevant signature algorithm
370  if(osStrcmp(keyPair->ecPublicKey.curve->name, "secp256r1") == 0 &&
371  osStrcmp(keyPair->ecPrivateKey.curve->name, "secp256r1") == 0)
372  {
373  //ECDSA using P-256 and SHA-256
374  osStrcpy(keyPair->alg, "ES256");
375  }
376  else if(osStrcmp(keyPair->ecPublicKey.curve->name, "secp384r1") == 0 &&
377  osStrcmp(keyPair->ecPrivateKey.curve->name, "secp384r1") == 0)
378  {
379  //ECDSA using P-384 and SHA-384
380  osStrcpy(keyPair->alg, "ES384");
381  }
382  else if(osStrcmp(keyPair->ecPublicKey.curve->name, "secp521r1") == 0 &&
383  osStrcmp(keyPair->ecPrivateKey.curve->name, "secp521r1") == 0)
384  {
385  //ECDSA using P-521 and SHA-512
386  osStrcpy(keyPair->alg, "ES512");
387  }
388  else
389  {
390  //Report an error
391  error = ERROR_INVALID_KEY;
392  }
393  }
394  }
395  else
396 #endif
397 #if (ACME_CLIENT_ED25519_SUPPORT == ENABLED)
398  //Ed22519 public key?
400  {
401  //Save public key type
402  keyPair->type = X509_KEY_TYPE_ED25519;
403 
404  //Initialize EdDSA public and private keys
407 
408  //Extract the EdDSA public key from the certificate
409  error = pemImportEddsaCertPublicKey(&keyPair->eddsaPublicKey, cert,
410  certLen);
411 
412  //Check status code
413  if(!error)
414  {
415  //Decode the PEM file that contains the EdDSA private key
416  error = pemImportEddsaPrivateKey(&keyPair->eddsaPrivateKey,
417  privateKey, privateKeyLen, password);
418  }
419 
420  //Check status code
421  if(!error)
422  {
423  //Valid Ed25519 key pair?
424  if(keyPair->eddsaPublicKey.curve == ED25519_CURVE &&
425  keyPair->eddsaPrivateKey.curve == ED25519_CURVE)
426  {
427  //Select EdDSA keys
428  keyPair->publicKey = &keyPair->eddsaPublicKey;
429  keyPair->privateKey = &keyPair->eddsaPrivateKey;
430 
431  //Select the relevant signature algorithm
432  osStrcpy(keyPair->alg, "EdDSA");
433  }
434  else
435  {
436  //Report an error
437  error = ERROR_INVALID_KEY;
438  }
439  }
440  }
441  else
442 #endif
443 #if (ACME_CLIENT_ED448_SUPPORT == ENABLED)
444  //Ed448 public key?
446  {
447  //Save public key type
448  keyPair->type = X509_KEY_TYPE_ED448;
449 
450  //Initialize EdDSA public and private keys
453 
454  //Extract the EdDSA public key from the certificate
455  error = pemImportEddsaCertPublicKey(&keyPair->eddsaPublicKey, cert,
456  certLen);
457 
458  //Check status code
459  if(!error)
460  {
461  //Decode the PEM file that contains the EdDSA private key
462  error = pemImportEddsaPrivateKey(&keyPair->eddsaPrivateKey,
463  privateKey, privateKeyLen, password);
464  }
465 
466  //Check status code
467  if(!error)
468  {
469  //Valid Ed448 key pair?
470  if(keyPair->eddsaPublicKey.curve == ED448_CURVE &&
471  keyPair->eddsaPrivateKey.curve == ED448_CURVE)
472  {
473  //Select EdDSA keys
474  keyPair->publicKey = &keyPair->eddsaPublicKey;
475  keyPair->privateKey = &keyPair->eddsaPrivateKey;
476 
477  //Select the relevant signature algorithm
478  osStrcpy(keyPair->alg, "EdDSA");
479  }
480  else
481  {
482  //Report an error
483  error = ERROR_INVALID_KEY;
484  }
485  }
486  }
487  else
488 #endif
489  //Invalid public key?
490  {
491  //The supplied public key is not valid
492  error = ERROR_INVALID_KEY;
493  }
494 
495  //Any error to report?
496  if(error)
497  {
498  //Clean up side effects
499  acmeClientUnloadKeyPair(keyPair);
500  }
501 
502  //Return status code
503  return error;
504 }
505 
506 
507 /**
508  * @brief Unload public/private key pair
509  * @param[in] keyPair Pointer to the key pair
510  **/
511 
513 {
514 #if (ACME_CLIENT_RSA_SUPPORT == ENABLED)
515  //RSA key pair?
516  if(keyPair->type == X509_KEY_TYPE_RSA)
517  {
518  //Release RSA public and private keys
519  rsaFreePublicKey(&keyPair->rsaPublicKey);
520  rsaFreePrivateKey(&keyPair->rsaPrivateKey);
521  }
522  else
523 #endif
524 #if (ACME_CLIENT_ECDSA_SUPPORT == ENABLED)
525  //EC key pair?
526  if(keyPair->type == X509_KEY_TYPE_EC)
527  {
528  //Release EC public and private keys
529  ecFreePublicKey(&keyPair->ecPublicKey);
530  ecFreePrivateKey(&keyPair->ecPrivateKey);
531  }
532  else
533 #endif
534 #if (ACME_CLIENT_ED25519_SUPPORT == ENABLED) || \
535  (ACME_CLIENT_ED448_SUPPORT == ENABLED)
536  //EdDSA key pair?
537  if(keyPair->type == X509_KEY_TYPE_ED25519 ||
538  keyPair->type == X509_KEY_TYPE_ED448)
539  {
540  //Release EdDSA public and private keys
543  }
544  else
545 #endif
546  //Invalid key pair?
547  {
548  //Just for sanity
549  }
550 
551  //Clear key pair
552  osMemset(keyPair, 0, sizeof(AcmeKeyPair));
553 }
554 
555 
556 /**
557  * @brief Send HTTP request
558  * @param[in] context Pointer to the ACME client context
559  * @return Error code
560  **/
561 
563 {
564  error_t error;
565  size_t n;
566 
567  //Initialize status code
568  error = NO_ERROR;
569 
570  //Check HTTP request state
571  if(context->requestState == ACME_REQ_STATE_SEND_HEADER)
572  {
573  //Send HTTP request header
574  error = httpClientWriteHeader(&context->httpClientContext);
575 
576  //Check status code
577  if(!error)
578  {
579  //Check whether the HTTP request contains a body
580  if(context->bufferLen > 0)
581  {
582  //Debug message
583  TRACE_DEBUG("HTTP request body (%" PRIuSIZE " bytes):\r\n", context->bufferLen);
584  TRACE_DEBUG("%s\r\n\r\n", context->buffer);
585 
586  //Point to the first byte of the body
587  context->bufferPos = 0;
588 
589  //Send HTTP request body
590  context->requestState = ACME_REQ_STATE_SEND_BODY;
591  }
592  else
593  {
594  //Receive HTTP response header
595  context->requestState = ACME_REQ_STATE_RECEIVE_HEADER;
596  }
597  }
598  }
599  else if(context->requestState == ACME_REQ_STATE_SEND_BODY)
600  {
601  //Send HTTP request body
602  if(context->bufferPos < context->bufferLen)
603  {
604  //Send more data
605  error = httpClientWriteBody(&context->httpClientContext,
606  context->buffer + context->bufferPos,
607  context->bufferLen - context->bufferPos, &n, 0);
608 
609  //Check status code
610  if(!error)
611  {
612  //Advance data pointer
613  context->bufferPos += n;
614  }
615  }
616  else
617  {
618  //Update HTTP request state
619  context->requestState = ACME_REQ_STATE_RECEIVE_HEADER;
620  }
621  }
622  else if(context->requestState == ACME_REQ_STATE_RECEIVE_HEADER)
623  {
624  //Receive HTTP response header
625  error = httpClientReadHeader(&context->httpClientContext);
626 
627  //Check status code
628  if(!error)
629  {
630  //Update HTTP request state
631  context->requestState = ACME_REQ_STATE_PARSE_HEADER;
632  }
633  }
634  else if(context->requestState == ACME_REQ_STATE_PARSE_HEADER)
635  {
636  //Parse HTTP response header
637  error = acmeClientParseResponseHeader(context);
638 
639  //Check status code
640  if(!error)
641  {
642  //Flush the receive buffer
643  context->bufferLen = 0;
644  context->bufferPos = 0;
645 
646  //Update HTTP request state
647  context->requestState = ACME_REQ_STATE_RECEIVE_BODY;
648  }
649  }
650  else if(context->requestState == ACME_REQ_STATE_RECEIVE_BODY)
651  {
652  //Receive HTTP response body
653  if(context->bufferLen < ACME_CLIENT_BUFFER_SIZE)
654  {
655  //Receive more data
656  error = httpClientReadBody(&context->httpClientContext,
657  context->buffer + context->bufferLen,
658  ACME_CLIENT_BUFFER_SIZE - context->bufferLen, &n, 0);
659 
660  //Check status code
661  if(error == NO_ERROR)
662  {
663  //Advance data pointer
664  context->bufferLen += n;
665  }
666  else if(error == ERROR_END_OF_STREAM)
667  {
668  //The end of the response body has been reached
669  error = NO_ERROR;
670 
671  //Update HTTP request state
672  context->requestState = ACME_REQ_STATE_CLOSE_BODY;
673  }
674  else
675  {
676  //Just for sanity
677  }
678  }
679  else
680  {
681  //Update HTTP request state
682  context->requestState = ACME_REQ_STATE_CLOSE_BODY;
683  }
684  }
685  else if(context->requestState == ACME_REQ_STATE_CLOSE_BODY)
686  {
687  //Close HTTP response body
688  error = httpClientCloseBody(&context->httpClientContext);
689 
690  //Check status code
691  if(!error)
692  {
693  //Properly terminate the body with a NULL character
694  context->buffer[context->bufferLen] = '\0';
695 
696  //Debug message
697  TRACE_DEBUG("HTTP response body (%" PRIuSIZE " bytes):\r\n", context->bufferLen);
698  TRACE_DEBUG("%s\r\n\r\n", context->buffer);
699 
700  //Clear error description
701  context->errorType[0] = '\0';
702 
703  //Check HTTP status code
704  if(!HTTP_STATUS_CODE_2YZ(context->statusCode))
705  {
706  //When the server responds with an error status, it should provide
707  //additional information using a problem document (refer to RFC 8555,
708  //section 6.7)
710 
711  //An error response with the "badNonce" error type must include a
712  //Replay-Nonce header field with a fresh nonce that the server will
713  //accept in a retry of the original query
714  if(osStrcmp(context->errorType, "urn:ietf:params:acme:error:badNonce") == 0 &&
715  context->badNonceErrors < ACME_CLIENT_MAX_BAD_NONCE_ERRORS &&
716  context->nonce[0] != '\0')
717  {
718  //Increment error counter
719  context->badNonceErrors++;
720 
721  //On receiving such a response, a client should retry the request
722  //using the new nonce (refer to RFC 8555, section 6.5)
723  context->requestState = ACME_REQ_STATE_INIT;
724  }
725  else
726  {
727  //Reset error counter
728  context->badNonceErrors = 0;
729  //Update HTTP request state
730  context->requestState = ACME_REQ_STATE_PARSE_BODY;
731  }
732  }
733  else
734  {
735  //Reset error counter
736  context->badNonceErrors = 0;
737  //Update HTTP request state
738  context->requestState = ACME_REQ_STATE_PARSE_BODY;
739  }
740  }
741  }
742  else
743  {
744  //Invalid state
745  error = ERROR_WRONG_STATE;
746  }
747 
748  //Return status code
749  return error;
750 }
751 
752 
753 /**
754  * @brief Format HTTP request header
755  * @param[in] context Pointer to the ACME client context
756  * @param[in] method NULL-terminating string containing the HTTP method
757  * @param[in] url Target URL
758  * @return Error code
759  **/
760 
762  const char_t *method, const char_t *url)
763 {
764  error_t error;
765  const char_t *path;
766 
767  //Make sure the URL is valid
768  if(url == NULL || url[0] == '\0')
770 
771  //Create a new HTTP request
772  error = httpClientCreateRequest(&context->httpClientContext);
773  //Any error to report?
774  if(error)
775  return error;
776 
777  //Set HTTP request method
778  error = httpClientSetMethod(&context->httpClientContext, method);
779  //Any error to report?
780  if(error)
781  return error;
782 
783  //Get the path portion of the URL
784  path = acmeClientGetPath(url);
785 
786  //The URI identifies a particular resource
787  error = httpClientSetUri(&context->httpClientContext, path);
788  //Any error to report?
789  if(error)
790  return error;
791 
792  //A client must send a Host header field in all HTTP/1.1 requests (refer
793  //to RFC 7230, section 5.4)
794  if(context->serverPort == HTTPS_PORT)
795  {
796  //A host without any trailing port information implies the default port
797  //for the service requested
798  error = httpClientAddHeaderField(&context->httpClientContext, "Host",
799  context->serverName);
800  }
801  else
802  {
803  //Append the port number information to the host
804  error = httpClientFormatHeaderField(&context->httpClientContext,
805  "Host", "%s:%" PRIu16, context->serverName, context->serverPort);
806  }
807 
808  //Any error to report?
809  if(error)
810  return error;
811 
812  //ACME clients must send a User-Agent header field (refer to RFC 8555,
813  //section 6.1)
814  error = httpClientAddHeaderField(&context->httpClientContext, "User-Agent",
815  "Mozilla/5.0");
816  //Any error to report?
817  if(error)
818  return error;
819 
820  //Check ACME client state
821  if(context->state == ACME_CLIENT_STATE_DOWNLOAD_CERT)
822  {
823  //The default format is application/pem-certificate-chain (refer to
824  //RFC 8555, section 7.4.2)
825  error = httpClientAddHeaderField(&context->httpClientContext, "Accept",
826  "application/pem-certificate-chain");
827  //Any error to report?
828  if(error)
829  return error;
830  }
831 
832  //POST request?
833  if(osStrcmp(method, "POST") == 0)
834  {
835  //Client requests must have the Content-Type header field set to
836  //"application/jose+json" (refer to RFC 8555, section 6.2)
837  error = httpClientAddHeaderField(&context->httpClientContext,
838  "Content-Type", "application/jose+json");
839  //Any error to report?
840  if(error)
841  return error;
842 
843  //Specify the length of the request body
844  error = httpClientSetContentLength(&context->httpClientContext,
845  context->bufferLen);
846  //Any error to report?
847  if(error)
848  return error;
849 
850  //Once a nonce value has appeared in an ACME request, the server will
851  //consider it invalid (refer to RFC 8555, section 6.5)
852  context->nonce[0] = '\0';
853  }
854  else
855  {
856  //The HTTP request body is empty
857  context->bufferLen = 0;
858  }
859 
860  //Return status code
861  return error;
862 }
863 
864 
865 /**
866  * @brief Format JWS protected header
867  * @param[in] keyPair Pointer to the key pair
868  * @param[in] kid Key identifier (account URL)
869  * @param[in] nonce Unique value that enables the verifier of a JWS to
870  * recognize when replay has occurred
871  * @param[in] url URL to which the client is directing the request
872  * @param[out] buffer Output buffer where to store the JSON object
873  * @param[out] written Length of the resulting JSON object
874  * @return Error code
875  **/
876 
878  const char_t *kid, const char_t *nonce, const char_t *url,
879  char_t *buffer, size_t *written)
880 {
881  error_t error;
882  int_t ret;
883  size_t n;
884  char_t *protected;
885  json_t *protectedObj;
886 
887  //Initialize status code
888  error = NO_ERROR;
889 
890  //Initialize pointer
891  protected = NULL;
892 
893  //Initialize JSON object
894  protectedObj = json_object();
895 
896  //Start of exception handling block
897  do
898  {
899  //The "alg" (algorithm) Header Parameter identifies the cryptographic
900  //algorithm used to secure the JWS (refer to RFC 7515, section 4.1.1)
901  ret = json_object_set_new(protectedObj, "alg", json_string(keyPair->alg));
902  //Any error to report?
903  if(ret != 0)
904  break;
905 
906  //The "jwk" and "kid" fields are mutually exclusive (refer to RFC 8555,
907  //section 6.2)
908  if(kid == NULL)
909  {
910  //Export the public key to JWK format
911  error = acmeClientFormatJwk(keyPair, buffer, &n, FALSE);
912  //Any error to report?
913  if(error)
914  break;
915 
916  //For newAccount requests, and for revokeCert requests authenticated by
917  //a certificate key, there must be a "jwk" field
918  ret = json_object_set_new(protectedObj, "jwk", json_loads(buffer, 0, NULL));
919  //Any error to report?
920  if(ret != 0)
921  break;
922  }
923  else
924  {
925  //For all other requests, the request is signed using an existing
926  //account, and there must be a "kid" field
927  ret = json_object_set_new(protectedObj, "kid", json_string(kid));
928  //Any error to report?
929  if(ret != 0)
930  break;
931  }
932 
933  //Valid nonce?
934  if(nonce != NULL)
935  {
936  //The "nonce" header parameter must be carried in the protected header
937  //of the JWS (refer to RFC 8555, section 6.5.2)
938  ret = json_object_set_new(protectedObj, "nonce", json_string(nonce));
939  //Any error to report?
940  if(ret != 0)
941  break;
942  }
943 
944  //The JWS protected header must include an "url" field
945  ret = json_object_set_new(protectedObj, "url", json_string(url));
946  //Any error to report?
947  if(ret != 0)
948  break;
949 
950  //Generate the JSON representation of the JWK object
951  protected = json_dumps(protectedObj, JSON_COMPACT);
952 
953  //End of exception handling block
954  } while(0);
955 
956  //Valid JSON representation?
957  if(protected != NULL)
958  {
959  //Copy JSON string
960  osStrcpy(buffer, protected);
961  //Total number of bytes that have been written
962  *written = osStrlen(protected);
963 
964  //Release JSON string
965  jsonp_free(protected);
966  }
967  else
968  {
969  //Report an error
970  error = ERROR_FAILURE;
971  }
972 
973  //Release JSON object
974  json_decref(protectedObj);
975 
976  //Return status code
977  return error;
978 }
979 
980 
981 /**
982  * @brief Export a public key to JWK format
983  * @param[in] keyPair Pointer to the key pair
984  * @param[out] buffer Output buffer where to store the JSON representation
985  * @param[out] written Length of the resulting JSON representation
986  * @param[in] sort Sort members of the JWK representation in lexicographic order
987  * @return Error code
988  **/
989 
991  size_t *written, bool_t sort)
992 {
993  error_t error;
994 
995 #if (ACME_CLIENT_RSA_SUPPORT == ENABLED)
996  //RSA public key?
997  if(keyPair->type == X509_KEY_TYPE_RSA)
998  {
999  //Export the RSA public key to JWK format
1000  error = jwkExportRsaPublicKey(&keyPair->rsaPublicKey, buffer, written,
1001  sort);
1002  }
1003  else
1004 #endif
1005 #if (ACME_CLIENT_ECDSA_SUPPORT == ENABLED)
1006  //EC public key?
1007  if(keyPair->type == X509_KEY_TYPE_EC)
1008  {
1009  //Export the EC public key to JWK format
1010  error = jwkExportEcPublicKey(&keyPair->ecPublicKey, buffer, written,
1011  sort);
1012  }
1013  else
1014 #endif
1015 #if (ACME_CLIENT_ED25519_SUPPORT == ENABLED) || \
1016  (ACME_CLIENT_ED448_SUPPORT == ENABLED)
1017  //EdDSA public key?
1018  if(keyPair->type == X509_KEY_TYPE_ED25519 ||
1019  keyPair->type == X509_KEY_TYPE_ED448)
1020  {
1021  //Export the EdDSA public key to JWK format
1022  error = jwkExportEddsaPublicKey(&keyPair->eddsaPublicKey, buffer,
1023  written, sort);
1024  }
1025  else
1026 #endif
1027  //Invalid public key?
1028  {
1029  //Report an error
1030  error = ERROR_INVALID_KEY;
1031  }
1032 
1033  //Return status code
1034  return error;
1035 }
1036 
1037 
1038 /**
1039  * @brief Generate CSR (Certificate Signing Request)
1040  * @param[in] context Pointer to the ACME client context
1041  * @param[out] buffer Output buffer where to store the CSR
1042  * @param[out] written Length of the resulting CSR
1043  * @return Error code
1044  **/
1045 
1047  size_t *written)
1048 {
1049  error_t error;
1050  uint_t i;
1051  X509CertRequestInfo *certReqInfo;
1052  X509SubjectAltName *subjectAltName;
1053  X509SignAlgoId signatureAlgo;
1054 
1055  //Initialize status code
1056  error = NO_ERROR;
1057 
1058  //Allocate a memory buffer to hold the certificate request information
1059  certReqInfo = cryptoAllocMem(sizeof(X509CertRequestInfo));
1060 
1061  //Successful memory allocation?
1062  if(certReqInfo != NULL)
1063  {
1064  //Clear certificate request information
1065  osMemset(certReqInfo, 0, sizeof(X509CertRequestInfo));
1066 
1067  //The CSR must indicate the exact same set of requested identifiers as the
1068  //initial newOrder request (refer to RFC 8555, section 7.4)
1069  certReqInfo->subject.commonName.value = context->identifiers[0].value;
1070  certReqInfo->subject.commonName.length = osStrlen(context->identifiers[0].value);
1071 
1072  //The Subject Alternative Name extension allows identities to be bound
1073  //to the subject of the certificate. These identities may be included
1074  //in addition to or in place of the identity in the subject field of the
1075  //certificate (refer to RFC 8555, section 4.2.1.6)
1076  subjectAltName = &certReqInfo->attributes.extensionReq.subjectAltName;
1077 
1078  //The extension may contain multiple domain names
1079  subjectAltName->numGeneralNames = MIN(context->numIdentifiers,
1081 
1082  //Set the Subject Alternative Name extension
1083  for(i = 0; i < subjectAltName->numGeneralNames; i++)
1084  {
1085  subjectAltName->generalNames[i].type = X509_GENERAL_NAME_TYPE_DNS;
1086  subjectAltName->generalNames[i].value = context->identifiers[i].value;
1087  subjectAltName->generalNames[i].length = osStrlen(context->identifiers[i].value);
1088  }
1089 
1090 #if (ACME_CLIENT_RSA_SUPPORT == ENABLED)
1091  //RSA key pair?
1092  if(context->certKey.type == X509_KEY_TYPE_RSA)
1093  {
1094  //Set public key identifier
1096  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(RSA_ENCRYPTION_OID);
1097 
1098  //Select the signature algorithm
1099  signatureAlgo.oid.value = SHA256_WITH_RSA_ENCRYPTION_OID;
1100  signatureAlgo.oid.length = sizeof(SHA256_WITH_RSA_ENCRYPTION_OID);
1101  }
1102  else
1103 #endif
1104 #if (ACME_CLIENT_ECDSA_SUPPORT == ENABLED)
1105  //EC key pair?
1106  if(context->certKey.type == X509_KEY_TYPE_EC)
1107  {
1108  X509OctetString *namedCurve;
1109 
1110  //Set public key identifier
1112  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(EC_PUBLIC_KEY_OID);
1113 
1114  //Select the signature algorithm
1115  signatureAlgo.oid.value = ECDSA_WITH_SHA256_OID;
1116  signatureAlgo.oid.length = sizeof(ECDSA_WITH_SHA256_OID);
1117 
1118  //Point to the named curve
1119  namedCurve = &certReqInfo->subjectPublicKeyInfo.ecParams.namedCurve;
1120 
1121  //Valid elliptic curve?
1122  if(context->certKey.ecPublicKey.curve != NULL)
1123  {
1124  //Select the relevant named curve
1125  namedCurve->value = context->certKey.ecPublicKey.curve->oid;
1126  namedCurve->length = context->certKey.ecPublicKey.curve->oidSize;
1127  }
1128  else
1129  {
1130  //Report an error
1131  error = ERROR_INVALID_KEY;
1132  }
1133  }
1134  else
1135 #endif
1136 #if (ACME_CLIENT_ED25519_SUPPORT == ENABLED)
1137  //Ed25519 key pair?
1138  if(context->certKey.type == X509_KEY_TYPE_ED25519)
1139  {
1140  //Set public key identifier
1141  certReqInfo->subjectPublicKeyInfo.oid.value = ED25519_OID;
1142  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(ED25519_OID);
1143 
1144  //Select the signature algorithm
1145  signatureAlgo.oid.value = ED25519_OID;
1146  signatureAlgo.oid.length = sizeof(ED25519_OID);
1147  }
1148  else
1149 #endif
1150 #if (ACME_CLIENT_ED448_SUPPORT == ENABLED)
1151  //Ed448 key pair?
1152  if(context->certKey.type == X509_KEY_TYPE_ED448)
1153  {
1154  //Set public key identifier
1155  certReqInfo->subjectPublicKeyInfo.oid.value = ED448_OID;
1156  certReqInfo->subjectPublicKeyInfo.oid.length = sizeof(ED448_OID);
1157 
1158  //Select the signature algorithm
1159  signatureAlgo.oid.value = ED448_OID;
1160  signatureAlgo.oid.length = sizeof(ED448_OID);
1161  }
1162  else
1163 #endif
1164  //Invalid key pair?
1165  {
1166  //Report an error
1167  error = ERROR_INVALID_KEY;
1168  }
1169 
1170  //Check status code
1171  if(!error)
1172  {
1173  //The CSR is signed by the private key corresponding to the public key
1174  error = x509CreateCsr(context->prngAlgo, context->prngContext,
1175  certReqInfo, context->certKey.publicKey, &signatureAlgo,
1176  context->certKey.privateKey, (uint8_t *) buffer, written);
1177  }
1178 
1179  //Release previously allocated memory
1180  cryptoFreeMem(certReqInfo);
1181  }
1182  else
1183  {
1184  //Failed to allocate memory
1185  error = ERROR_OUT_OF_MEMORY;
1186  }
1187 
1188  //Return status code
1189  return error;
1190 }
1191 
1192 
1193 /**
1194  * @brief Parse HTTP response header
1195  * @param[in] context Pointer to the ACME client context
1196  * @return Error code
1197  **/
1198 
1200 {
1201  error_t error;
1202  size_t n;
1203  char_t *p;
1204  const char_t *nonce;
1205  const char_t *location;
1206  const char_t *contentType;
1207 
1208  //Get HTTP response status code
1209  context->statusCode = httpClientGetStatus(&context->httpClientContext);
1210 
1211  //The server must include a Replay-Nonce header field in every successful
1212  //response to a POST request and should provide it in error responses as well
1213  if(context->state != ACME_CLIENT_STATE_DIRECTORY)
1214  {
1215  //The Replay-Nonce HTTP header field includes a server-generated value
1216  //that the server can use to detect unauthorized replay in future client
1217  //requests (refer to RFC 8555, section 6.5.1)
1218  nonce = httpClientGetHeaderField(&context->httpClientContext,
1219  "Replay-Nonce");
1220 
1221  //Replay-Nonce header field found?
1222  if(nonce != NULL)
1223  {
1224  //Check the length of the header field value
1226  {
1227  //The value of the Replay-Nonce header field must be an octet string
1228  //encoded according to the Base64url
1229  error = base64urlDecode(nonce, osStrlen(nonce), NULL, &n);
1230 
1231  //Clients must ignore invalid Replay-Nonce values
1232  if(!error)
1233  {
1234  //Copy the value of the Replay-Nonce header field
1235  osStrcpy(context->nonce, nonce);
1236  }
1237  }
1238  }
1239  }
1240 
1241  //When the server responds to a newAccount or a newOrder requests it must
1242  //return a Location header field pointing to the created resource
1243  if(context->state == ACME_CLIENT_STATE_NEW_ACCOUNT)
1244  {
1245  //The server returns the account URL in a Location header field (refer
1246  //to RFC 8555, section 7.3)
1247  location = httpClientGetHeaderField(&context->httpClientContext,
1248  "Location");
1249 
1250  //Location header field found?
1251  if(location != NULL)
1252  {
1253  //Check the length of the header field value
1254  if(osStrlen(location) <= ACME_CLIENT_MAX_URL_LEN)
1255  {
1256  //Copy the value of the Location header field
1257  osStrcpy(context->account.url, location);
1258  }
1259  }
1260  }
1261  else if(context->state == ACME_CLIENT_STATE_NEW_ORDER)
1262  {
1263  //The server returns the order identifier in a Location header field
1264  location = httpClientGetHeaderField(&context->httpClientContext,
1265  "Location");
1266 
1267  //Location header field found?
1268  if(location != NULL)
1269  {
1270  //Check the length of the header field value
1271  if(osStrlen(location) <= ACME_CLIENT_MAX_URL_LEN)
1272  {
1273  //Copy the value of the Location header field
1274  osStrcpy(context->order.url, location);
1275  }
1276  }
1277  }
1278  else
1279  {
1280  //Just for sanity
1281  }
1282 
1283  //Get the Content-Type header field
1284  contentType = httpClientGetHeaderField(&context->httpClientContext,
1285  "Content-Type");
1286 
1287  //Content-Type header field found?
1288  if(contentType != NULL)
1289  {
1290  //Retrieve the header field value
1291  n = osStrlen(contentType);
1292  //Limit the length of the string
1294 
1295  //Save the media type
1296  osStrncpy(context->contentType, contentType, n);
1297  //Properly terminate the string with a NULL character
1298  context->contentType[n] = '\0';
1299 
1300  //Discard the parameters that may follow the type/subtype
1301  osStrtok_r(context->contentType, "; \t", &p);
1302  }
1303  else
1304  {
1305  //The Content-Type header field is not present in the response
1306  context->contentType[0] = '\0';
1307  }
1308 
1309  //Successful processing
1310  return NO_ERROR;
1311 }
1312 
1313 
1314 /**
1315  * @brief Parse error response
1316  * @param[in] context Pointer to the ACME client context
1317  * @return Error code
1318  **/
1319 
1321 {
1322  error_t error;
1323  const char_t *type;
1324  json_t *rootObj;
1325  json_t *typeObj;
1326 
1327  //Initialize status code
1328  error = ERROR_INVALID_RESPONSE;
1329 
1330  //Clear error type
1331  context->errorType[0] = '\0';
1332 
1333  //Check the media type
1334  if(osStrcasecmp(context->contentType, "application/problem+json") == 0)
1335  {
1336  //When the server responds with an error status, it should provide
1337  //additional information using a problem document (refer to RFC 7807)
1338  rootObj = json_loads(context->buffer, 0, NULL);
1339 
1340  //Successful parsing?
1341  if(json_is_object(rootObj))
1342  {
1343  //The "type" string is used as the primary identifier for the problem
1344  //type
1345  typeObj = json_object_get(rootObj, "type");
1346 
1347  //The object must be a valid string
1348  if(json_is_string(typeObj))
1349  {
1350  //Get the value of the string
1351  type = json_string_value(typeObj);
1352 
1353  //Check the length of the URN
1355  {
1356  //Save the error type
1357  osStrcpy(context->errorType, type);
1358 
1359  //Successful parsing
1360  error = NO_ERROR;
1361  }
1362  }
1363  }
1364 
1365  //Release JSON object
1366  json_decref(rootObj);
1367  }
1368 
1369  //Return status code
1370  return error;
1371 }
1372 
1373 
1374 /**
1375  * @brief Extract the path name from a given URL
1376  * @brief param[in] NULL-terminated string that contains the URL
1377  * @return Path component of the URL
1378  **/
1379 
1380 const char_t *acmeClientGetPath(const char_t *url)
1381 {
1382  const char_t *p;
1383 
1384  //Default path name
1385  static const char_t defaultPath[] = "/";
1386 
1387  //The scheme is followed by a colon and two forward slashes
1388  p = osStrstr(url, "://");
1389 
1390  //The path name begins with a single forward slash
1391  if(p != NULL)
1392  {
1393  p = osStrchr(p + 3, '/');
1394  }
1395  else
1396  {
1397  p = osStrchr(url, '/');
1398  }
1399 
1400  //A path is always defined for a URI, though the defined path may be empty
1401  if(p == NULL)
1402  {
1403  p = defaultPath;
1404  }
1405 
1406  //Return the path component
1407  return p;
1408 }
1409 
1410 #endif
EddsaPrivateKey eddsaPrivateKey
Definition: acme_client.h:429
@ X509_KEY_TYPE_RSA
Definition: x509_common.h:635
#define osStrchr(s, c)
Definition: os_port.h:198
X509GeneralNameType type
Definition: x509_common.h:908
error_t httpClientCloseBody(HttpClientContext *context)
Close HTTP request or response body.
Definition: http_client.c:2012
int bool_t
Definition: compiler_port.h:61
CSR (Certificate Signing Request) generation.
void rsaFreePublicKey(RsaPublicKey *key)
Release an RSA public key.
Definition: rsa.c:113
error_t pemImportEddsaPrivateKey(EddsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode a PEM file containing a EdDSA private key.
Definition: pem_import.c:1228
error_t httpClientSetUri(HttpClientContext *context, const char_t *uri)
Set request URI.
Definition: http_client.c:462
signed int int_t
Definition: compiler_port.h:56
EddsaPublicKey eddsaPublicKey
Definition: acme_client.h:428
error_t acmeClientLoadKeyPair(AcmeKeyPair *keyPair, const char_t *publicKey, size_t publicKeyLen, const char_t *privateKey, size_t privateKeyLen, const char_t *password)
Load public/private key pair.
const EcCurve * curve
Elliptic curve parameters.
Definition: eddsa.h:76
#define HTTP_STATUS_CODE_2YZ(code)
Definition: http_common.h:44
error_t httpClientReadBody(HttpClientContext *context, void *data, size_t size, size_t *received, uint_t flags)
Read HTTP response body.
Definition: http_client.c:1646
OID (Object Identifier)
error_t jwkExportRsaPublicKey(const RsaPublicKey *publicKey, char_t *buffer, size_t *written, bool_t sort)
Export an RSA public key to JWK format.
void eddsaFreePrivateKey(EddsaPrivateKey *key)
Release an EdDSA private key.
Definition: eddsa.c:95
void eddsaInitPrivateKey(EddsaPrivateKey *key)
Initialize an EdDSA private key.
Definition: eddsa.c:75
uint8_t p
Definition: ndp.h:300
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:433
X509OctetString oid
Definition: x509_common.h:840
const void * publicKey
Definition: acme_client.h:416
error_t pemImportRsaPrivateKey(RsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode a PEM file containing an RSA private key.
Definition: pem_import.c:379
Helper functions for ACME client.
const uint8_t EC_PUBLIC_KEY_OID[7]
Definition: ec.c:44
X509EcParameters ecParams
Definition: x509_common.h:850
@ ACME_REQ_STATE_PARSE_BODY
Definition: acme_client.h:297
RsaPrivateKey rsaPrivateKey
Definition: acme_client.h:420
#define ED25519_CURVE
Definition: ec_curves.h:72
uint8_t type
Definition: coap_common.h:176
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define ED448_CURVE
Definition: ec_curves.h:73
X509Extensions extensionReq
Definition: x509_common.h:1298
error_t jwkExportEcPublicKey(const EcPublicKey *publicKey, char_t *buffer, size_t *written, bool_t sort)
Export an EC public key to JWK format.
#define ACME_CLIENT_BUFFER_SIZE
Definition: acme_client.h:166
#define osStrcmp(s1, s2)
Definition: os_port.h:174
#define osStrlen(s)
Definition: os_port.h:168
const uint8_t ECDSA_WITH_SHA256_OID[8]
Definition: ecdsa.c:49
@ ERROR_END_OF_STREAM
Definition: error.h:211
error_t httpClientSetContentLength(HttpClientContext *context, size_t length)
Set the length of the HTTP request body.
Definition: http_client.c:987
JOSE (JSON Object Signing and Encryption)
#define X509_MAX_SUBJECT_ALT_NAMES
Definition: x509_common.h:429
error_t httpClientCreateRequest(HttpClientContext *context)
Create a new HTTP request.
Definition: http_client.c:365
size_t length
Definition: x509_common.h:692
X509String commonName
Definition: x509_common.h:725
void rsaInitPrivateKey(RsaPrivateKey *key)
Initialize an RSA private key.
Definition: rsa.c:126
const char_t * acmeClientGetPath(const char_t *url)
Extract the path name from a given URL.
@ ERROR_WRONG_STATE
Definition: error.h:210
@ ACME_CLIENT_STATE_NEW_ACCOUNT
Definition: acme_client.h:267
error_t acmeClientSendRequest(AcmeClientContext *context)
Send HTTP request.
@ X509_KEY_TYPE_EC
Definition: x509_common.h:638
X509SubjectPublicKeyInfo subjectPublicKeyInfo
Definition: x509_common.h:1311
@ ACME_CLIENT_STATE_NEW_ORDER
Definition: acme_client.h:271
error_t acmeClientGenerateCsr(AcmeClientContext *context, uint8_t *buffer, size_t *written)
Generate CSR (Certificate Signing Request)
#define FALSE
Definition: os_port.h:46
error_t acmeClientLoadCertKeyPair(AcmeKeyPair *keyPair, const char_t *cert, size_t certLen, const char_t *privateKey, size_t privateKeyLen, const char_t *password)
Load certificate/private key pair.
#define ACME_CLIENT_MAX_NONCE_LEN
Definition: acme_client.h:201
error_t acmeClientParseProblemDetails(AcmeClientContext *context)
Parse error response.
PEM file import functions.
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t httpClientWriteHeader(HttpClientContext *context)
Write HTTP request header.
Definition: http_client.c:1014
@ X509_GENERAL_NAME_TYPE_DNS
Definition: x509_common.h:569
error_t acmeClientFormatRequestHeader(AcmeClientContext *context, const char_t *method, const char_t *url)
Format HTTP request header.
const EcCurve * curve
Elliptic curve parameters.
Definition: eddsa.h:65
error_t
Error codes.
Definition: error.h:43
error_t httpClientFormatHeaderField(HttpClientContext *context, const char_t *name, const char_t *format,...)
Format an HTTP header field.
Definition: http_client.c:890
void ecInitPublicKey(EcPublicKey *key)
Initialize an EC public key.
Definition: ec.c:52
void rsaFreePrivateKey(RsaPrivateKey *key)
Release an RSA private key.
Definition: rsa.c:148
#define osStrtok_r(s, delim, last)
Definition: os_port.h:228
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.
error_t base64urlDecode(const char_t *input, size_t inputLen, void *output, size_t *outputLen)
Base64url decoding algorithm.
Definition: base64url.c:184
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
EcPrivateKey ecPrivateKey
Definition: acme_client.h:424
@ ACME_REQ_STATE_CLOSE_BODY
Definition: acme_client.h:298
const char_t * httpClientGetHeaderField(HttpClientContext *context, const char_t *name)
Retrieve the value of the specified header field name.
Definition: http_client.c:1539
error_t pemImportEcPrivateKey(EcPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode a PEM file containing an EC private key.
Definition: pem_import.c:945
#define osStrcasecmp(s1, s2)
Definition: os_port.h:186
Base64url encoding scheme.
@ ACME_REQ_STATE_INIT
Definition: acme_client.h:289
#define ACME_CLIENT_MAX_URN_LEN
Definition: acme_client.h:194
error_t acmeClientFormatJwk(const AcmeKeyPair *keyPair, char_t *buffer, size_t *written, bool_t sort)
Export a public key to JWK format.
#define ACME_CLIENT_MAX_URL_LEN
Definition: acme_client.h:187
void ecFreePrivateKey(EcPrivateKey *key)
Release an EC private key.
Definition: ec.c:100
EcPublicKey ecPublicKey
Definition: acme_client.h:423
X509OctetString oid
Definition: x509_common.h:1089
Public/private key pair.
Definition: acme_client.h:413
uint_t httpClientGetStatus(HttpClientContext *context)
Retrieve the HTTP status code of the response.
Definition: http_client.c:1512
#define MIN(a, b)
Definition: os_port.h:63
#define ACME_CLIENT_MAX_BAD_NONCE_ERRORS
Definition: acme_client.h:236
CertificationRequestInfo structure.
Definition: x509_common.h:1307
X509SubjectAltName subjectAltName
Definition: x509_common.h:1057
Subject Alternative Name extension.
Definition: x509_common.h:919
error_t jwkExportEddsaPublicKey(const EddsaPublicKey *publicKey, char_t *buffer, size_t *written, bool_t sort)
Export an EdDSA public key to JWK format.
const uint8_t SHA256_WITH_RSA_ENCRYPTION_OID[9]
Definition: rsa.c:65
X509OctetString namedCurve
Definition: x509_common.h:819
error_t httpClientReadHeader(HttpClientContext *context)
Read HTTP response header.
Definition: http_client.c:1372
X509KeyType pemGetPublicKeyType(const char_t *input, size_t length)
Extract the public key type from a PEM file.
Definition: pem_import.c:1373
const uint8_t ED448_OID[3]
Definition: ec_curves.c:114
@ ACME_REQ_STATE_RECEIVE_HEADER
Definition: acme_client.h:294
#define HTTPS_PORT
Definition: http_common.h:40
const uint8_t ED25519_OID[3]
Definition: ec_curves.c:112
const uint8_t RSA_ENCRYPTION_OID[9]
Definition: rsa.c:54
const char_t * value
Definition: x509_common.h:909
error_t pemImportEddsaCertPublicKey(EddsaPublicKey *publicKey, const char_t *input, size_t length)
Extract the EdDSA public key from a PEM certificate.
error_t pemImportRsaPublicKey(RsaPublicKey *publicKey, const char_t *input, size_t length)
Decode a PEM file containing an RSA public key.
Definition: pem_import.c:252
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
error_t httpClientAddHeaderField(HttpClientContext *context, const char_t *name, const char_t *value)
Add a header field to the HTTP request.
Definition: http_client.c:808
#define AcmeClientContext
Definition: acme_client.h:248
const char_t * value
Definition: x509_common.h:691
@ X509_KEY_TYPE_ED448
Definition: x509_common.h:643
uint8_t n
error_t httpClientWriteBody(HttpClientContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Write HTTP request body.
Definition: http_client.c:1137
error_t pemImportEcPublicKey(EcPublicKey *publicKey, const char_t *input, size_t length)
Decode a PEM file containing an EC public key.
Definition: pem_import.c:865
error_t pemImportRsaCertPublicKey(RsaPublicKey *publicKey, const char_t *input, size_t length)
Extract the RSA public key from a PEM certificate.
#define cryptoFreeMem(p)
Definition: crypto.h:826
void ecInitPrivateKey(EcPrivateKey *key)
Initialize an EC private key.
Definition: ec.c:80
#define osStrncpy(s1, s2, length)
Definition: os_port.h:216
@ ACME_REQ_STATE_SEND_HEADER
Definition: acme_client.h:291
char_t alg[8]
Definition: acme_client.h:415
#define cryptoAllocMem(size)
Definition: crypto.h:821
void eddsaFreePublicKey(EddsaPublicKey *key)
Release an EdDSA public key.
Definition: eddsa.c:63
@ ACME_REQ_STATE_PARSE_HEADER
Definition: acme_client.h:295
error_t acmeClientParseResponseHeader(AcmeClientContext *context)
Parse HTTP response header.
const uint8_t * value
Definition: x509_common.h:702
error_t pemImportEcCertPublicKey(EcPublicKey *publicKey, const char_t *input, size_t length)
Extract the EC public key from a PEM certificate.
@ ACME_CLIENT_STATE_DIRECTORY
Definition: acme_client.h:265
error_t httpClientSetMethod(HttpClientContext *context, const char_t *method)
Set HTTP request method.
Definition: http_client.c:402
void acmeClientUnloadKeyPair(AcmeKeyPair *keyPair)
Unload public/private key pair.
#define osStrstr(s1, s2)
Definition: os_port.h:204
error_t x509CreateCsr(const PrngAlgo *prngAlgo, void *prngContext, const X509CertRequestInfo *certReqInfo, const void *subjectPublicKey, const X509SignAlgoId *signatureAlgo, const void *signerPrivateKey, uint8_t *output, size_t *written)
Generate a CSR (Certificate Signing Request)
Octet string.
Definition: x509_common.h:701
@ ACME_REQ_STATE_RECEIVE_BODY
Definition: acme_client.h:296
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
@ X509_KEY_TYPE_ED25519
Definition: x509_common.h:641
@ ACME_REQ_STATE_SEND_BODY
Definition: acme_client.h:293
X509KeyType
Public Key types.
Definition: x509_common.h:633
const void * privateKey
Definition: acme_client.h:417
void eddsaInitPublicKey(EddsaPublicKey *key)
Initialize an EdDSA public key.
Definition: eddsa.c:48
X509Attributes attributes
Definition: x509_common.h:1312
X509GeneralName generalNames[X509_MAX_SUBJECT_ALT_NAMES]
Definition: x509_common.h:923
#define osStrcpy(s1, s2)
Definition: os_port.h:210
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
@ ERROR_INVALID_RESPONSE
Definition: error.h:71
RsaPublicKey rsaPublicKey
Definition: acme_client.h:419
ACME client (Automatic Certificate Management Environment)
X509KeyType type
Definition: acme_client.h:414
#define ACME_CLIENT_MAX_CONTENT_TYPE_LEN
Definition: acme_client.h:229
@ ACME_CLIENT_STATE_DOWNLOAD_CERT
Definition: acme_client.h:277
uint8_t nonce[]
Definition: ntp_common.h:233
Signature algorithm identifier.
Definition: x509_common.h:1088
@ ERROR_INVALID_KEY
Definition: error.h:106
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void rsaInitPublicKey(RsaPublicKey *key)
Initialize an RSA public key.
Definition: rsa.c:100
error_t pemImportEddsaPublicKey(EddsaPublicKey *publicKey, const char_t *input, size_t length)
Decode a PEM file containing a EdDSA public key.
Definition: pem_import.c:1148
void ecFreePublicKey(EcPublicKey *key)
Release an EC public key.
Definition: ec.c:68
PEM certificate public key import functions.
X509KeyType pemGetCertPublicKeyType(const char_t *input, size_t length)
Extract the type of the public key contained in a PEM certificate.