acme_new_account/acme-new-account.rs
1use jaws::Compact;
2use jaws::JWTFormat;
3use jaws::Token;
4use rsa::pkcs8::DecodePrivateKey;
5use serde_json::json;
6use sha2::Sha256;
7
8/// Create a JWT suitable as a new-account request in the ACME protocol.
9///
10/// The resulting JWT should look like this (in the example format from RFC8555):
11/// ```
12/// POST /acme/new-account HTTP/1.1
13/// Host: example.com
14/// Content-Type: application/jose+json
15///
16/// {
17///   "protected": base64url({
18///     "alg": "RS256",
19///     "jwk": {...
20///     },
21///     "nonce": "6S8IqOGY7eL2lsGoTZYifg",
22///     "url": "https://example.com/acme/new-account"
23///   }),
24///   "payload": base64url({
25///     "termsOfServiceAgreed": true,
26///     "contact": [
27///       "mailto:cert-admin@example.org",
28///       "mailto:admin@example.org"
29///     ]
30///   }),
31///   "signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
32/// }
33/// ```
34///
35/// For a more detailed explanation, see `rfc7515a2.rs`.
36fn main() {
37    // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38    // The key here is stored as a PKCS#8 PEM file, but you can leverage
39    // RustCrypto to load a variety of other formats.
40    let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41        env!("CARGO_MANIFEST_DIR"),
42        "/examples/rfc7515a2.pem"
43    )))
44    .unwrap();
45
46    // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47    // RsaPkcs1v15 is really an alias to the digital signature algorithm
48    // implementation in the `rsa` crate, but provided in JAWS to make
49    // it clear which types are compatible with JWTs.
50    let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
51
52    let payload = json!({
53      "termsOfServiceAgreed": true,
54      "contact": [
55        "mailto:cert-admin@example.org",
56        "mailto:admin@example.org"
57      ]
58    });
59
60    let header = json!({
61        "nonce": "6S8IqOGY7eL2lsGoTZYifg",
62        "url": "https://example.com/acme/new-account"
63    });
64
65    // Create a token with the default headers, and no custom headers.
66    let mut token = Token::new(payload, header, Compact);
67    // Request that the token header include a JWK field.
68    token.header_mut().key().derived();
69
70    // Sign the token with the algorithm and key we specified above.
71    let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
72
73    // Print the token in the ACME example format.
74    println!("{}", signed.formatted());
75}