Repository: poem-web/poem (language: rust)

Issue:
Acme-alpn does not work
## Expected Behavior
Example code should work

## Actual Behavior
```
2024-04-13T23:58:50.902818Z DEBUG poem::listener::acme::client: loading directory
2024-04-13T23:58:51.504439Z DEBUG poem::listener::acme::client: directory loaded new_nonce="https://acme-v02.api.letsencrypt.org/acme/new-nonce" new_account="https://acme-v02.api.letsencrypt.org/acme/new-acct" new_order="https://acme-v02.api.letsencrypt.org/acme/new-order"
2024-04-13T23:58:51.505264Z DEBUG poem::listener::acme::listener: issue certificate
2024-04-13T23:58:51.505257Z  INFO poem::server: listening name="hello-world" addr=socket://0.0.0.0:443
2024-04-13T23:58:51.505361Z DEBUG poem::listener::acme::client: creating acme account
2024-04-13T23:58:51.505366Z  INFO poem::server: server started name="hello-world"
2024-04-13T23:58:51.505417Z DEBUG poem::listener::acme::client: creating nonce
2024-04-13T23:58:51.716131Z DEBUG poem::listener::acme::client: nonce created nonce="V_63_Dn5pwrG1CrgKvsEODgmrYot6Vhx66ZN_8Fi2w3bqX9KOIU"
2024-04-13T23:58:51.716798Z DEBUG poem::listener::acme::jose: http request uri=https://acme-v02.api.letsencrypt.org/acme/new-acct
2024-04-13T23:58:51.904047Z ERROR poem::listener::acme::listener: failed to issue certificate error=unexpected status code: status = 415 Unsupported Media Type
```

## Steps to Reproduce the Problem

Take code in `exaples/poem/acme-alpn-01`
Change domain to yours
Run

## Specifications

- Version: 3.0.0 (f6bec886333a60e7f12eab9e0830cf9cae332029)
- Platform: Linux
- Subsystem: acme


Discussion / hints:

Fix patch:
diff --git a/poem/Cargo.toml b/poem/Cargo.toml
index 591a862b47..98579b4a80 100644
--- a/poem/Cargo.toml
+++ b/poem/Cargo.toml
@@ -150,7 +150,7 @@ unic-langid = { version = "0.9.0", optional = true, features = ["macros"] }
 intl-memoizer = { version = "0.5.1", optional = true }
 ring = { version = "0.17.7", optional = true }
 reqwest = { workspace = true, features = ["json"], optional = true }
-rcgen = { version = "0.13.0", optional = true }
+rcgen = { version = "0.12.0", optional = true }
 x509-parser = { version = "0.16.0", optional = true }
 tokio-metrics = { version = "0.3.0", optional = true }
 rust-embed = { version = "8.0", optional = true }
diff --git a/poem/src/listener/acme/jose.rs b/poem/src/listener/acme/jose.rs
index 58767b2289..e79bad5236 100644
--- a/poem/src/listener/acme/jose.rs
+++ b/poem/src/listener/acme/jose.rs
@@ -124,12 +124,12 @@ pub(crate) async fn request(
 
     let resp = cli
         .post(uri)
+        .header("content-type", "application/jose+json")
         .json(&Body {
             protected,
             payload,
             signature,
         })
-        .header("content-type", "application/jose+json")
         .send()
         .await
         .map_err(|err| {
diff --git a/poem/src/listener/acme/listener.rs b/poem/src/listener/acme/listener.rs
index a9b36b195a..160b09ffe1 100644
--- a/poem/src/listener/acme/listener.rs
+++ b/poem/src/listener/acme/listener.rs
@@ -5,7 +5,9 @@ use std::{
 };
 
 use http::uri::Scheme;
-use rcgen::{CertificateParams, CustomExtension, KeyPair, PKCS_ECDSA_P256_SHA256};
+use rcgen::{
+    Certificate, CertificateParams, CustomExtension, DistinguishedName, PKCS_ECDSA_P256_SHA256,
+};
 use tokio_rustls::{
     rustls::{
         crypto::ring::sign::any_ecdsa_type,
@@ -227,21 +229,21 @@ impl<T: Acceptor> Acceptor for AutoCertAcceptor<T> {
 }
 
 fn gen_acme_cert(domain: &str, acme_hash: &[u8]) -> IoResult<CertifiedKey> {
-    let keypair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).expect("create key pair");
-    let cert = CertificateParams::new(vec![domain.to_string()])
-        .and_then(|mut params| {
-            params.custom_extensions = vec![CustomExtension::new_acme_identifier(acme_hash)];
-            params.self_signed(&keypair)
-        })
-        .map_err(|err| {
-            IoError::new(
-                ErrorKind::Other,
-                format!("failed to generate acme certificate: {err}"),
-            )
-        })?;
-
-    let key = any_ecdsa_type(&PrivateKeyDer::Pkcs8(keypair.serialized_der().into())).unwrap();
-    Ok(CertifiedKey::new(vec![cert.der().clone()], key))
+    let mut params = CertificateParams::new(vec![domain.to_string()]);
+    params.alg = &PKCS_ECDSA_P256_SHA256;
+    params.custom_extensions = vec![CustomExtension::new_acme_identifier(acme_hash)];
+    let cert = Certificate::from_params(params)
+        .map_err(|_| IoError::new(ErrorKind::Other, "failed to generate acme certificate"))?;
+    let key = any_ecdsa_type(&PrivateKeyDer::Pkcs8(
+        cert.serialize_private_key_der().into(),
+    ))
+    .unwrap();
+    Ok(CertifiedKey::new(
+        vec![CertificateDer::from(cert.serialize_der().map_err(
+            |_| IoError::new(ErrorKind::Other, "failed to serialize acme certificate"),
+        )?)],
+        key,
+    ))
 }
 
 /// The result of [`issue_cert`] function.
@@ -341,23 +343,31 @@ pub async fn issue_cert<T: AsRef<str>>(
     }
 
     // send csr
-    let keypair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).expect("create key pair");
-    let request = CertificateParams::new(
+    let mut params = CertificateParams::new(
         domains
             .iter()
             .map(|domain| domain.as_ref().to_string())
             .collect::<Vec<_>>(),
-    )
-    .and_then(|params| params.serialize_request(&keypair))
-    .map_err(|err| {
+    );
+    params.distinguished_name = DistinguishedName::new();
+    params.alg = &PKCS_ECDSA_P256_SHA256;
+    let cert = Certificate::from_params(params).map_err(|err| {
         IoError::new(
             ErrorKind::Other,
             format!("failed create certificate request: {err}"),
         )
     })?;
+    let pk = any_ecdsa_type(&PrivateKeyDer::Pkcs8(
+        cert.serialize_private_key_der().into(),
+    ))
+    .unwrap();
+    let csr = cert.serialize_request_der().map_err(|err| {
+        IoError::new(
+            ErrorKind::Other,
+            format!("failed to serialize request der {err}"),
+        )
+    })?;
 
-    let pk = any_ecdsa_type(&PrivateKeyDer::Pkcs8(keypair.serialized_der().into())).unwrap();
-    let csr = request.der().as_ref();
     let order_resp = client.send_csr(&order_resp.finalize, &csr).await?;
 
     if order_resp.status == "invalid" {
@@ -393,7 +403,7 @@ pub async fn issue_cert<T: AsRef<str>>(
             )
         })?)
         .await?;
-    let pkey_pem = keypair.serialize_pem();
+    let pkey_pem = cert.serialize_private_key_pem();
     let cert_chain = rustls_pemfile::certs(&mut acme_cert_pem.as_slice())
         .collect::<Result<_, _>>()
         .map_err(|err| IoError::new(ErrorKind::Other, format!("invalid pem: {err}")))?;


Test patch: