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