ddns/core/parser/
sigin.rs1use rustls::{SignatureScheme, pki_types::SubjectPublicKeyInfoDer, sign::SigningKey};
2use snafu::{ResultExt, Snafu};
3use x509_parser::{
4 oid_registry::{
5 OID_EC_P256, OID_KEY_TYPE_EC_PUBLIC_KEY, OID_NIST_EC_P384, OID_PKCS1_RSAENCRYPTION,
6 OID_SIG_ED25519,
7 },
8 prelude::FromDer,
9 x509::SubjectPublicKeyInfo,
10};
11
12#[derive(Debug, Snafu)]
13#[snafu(module)]
14pub enum SignError {
15 #[snafu(display("failed to sign DHTTP identity data"))]
16 Identity {
17 source: dhttp_identity::identity::SignError,
18 },
19}
20
21#[derive(Debug, Snafu)]
22#[snafu(module)]
23pub enum VerifyError {
24 #[snafu(display("failed to verify DHTTP identity signature"))]
25 Identity {
26 source: dhttp_identity::identity::VerifyError,
27 },
28 #[snafu(display("unsupported signature scheme {scheme:?}"))]
29 UnsupportedScheme { scheme: SignatureScheme },
30 #[snafu(display("invalid certificate: {details}"))]
31 InvalidCertificate { details: String },
32 #[snafu(display("invalid PEM"))]
33 InvalidPem { source: std::io::Error },
34 #[snafu(display("invalid base64"))]
35 InvalidBase64 { source: base64::DecodeError },
36 #[snafu(display("io error"))]
37 Io { source: std::io::Error },
38}
39
40#[derive(Debug, Snafu)]
41#[snafu(module)]
42pub enum SignatureSchemeError {
43 #[snafu(display("unsupported public key type"))]
44 UnsupportedKey,
45}
46
47pub fn sign_with_key(key: &(impl SigningKey + ?Sized), data: &[u8]) -> Result<Vec<u8>, SignError> {
48 dhttp_identity::identity::sign_with_key(key, data).context(sign_error::IdentitySnafu)
49}
50
51pub(crate) fn signature_scheme(
52 spki: SubjectPublicKeyInfoDer<'_>,
53) -> Result<SignatureScheme, SignatureSchemeError> {
54 let Ok((_remain, spki)) = SubjectPublicKeyInfo::from_der(spki.as_ref()) else {
55 return signature_scheme_error::UnsupportedKeySnafu.fail();
56 };
57
58 if spki.algorithm.algorithm == OID_SIG_ED25519 {
59 return Ok(SignatureScheme::ED25519);
60 }
61
62 if spki.algorithm.algorithm == OID_PKCS1_RSAENCRYPTION {
63 return Ok(SignatureScheme::RSA_PSS_SHA512);
64 }
65
66 if spki.algorithm.algorithm != OID_KEY_TYPE_EC_PUBLIC_KEY {
67 return signature_scheme_error::UnsupportedKeySnafu.fail();
68 }
69
70 let Some(curve) = spki
71 .algorithm
72 .parameters
73 .as_ref()
74 .and_then(|parameters| parameters.as_oid().ok())
75 else {
76 return signature_scheme_error::UnsupportedKeySnafu.fail();
77 };
78
79 if curve == OID_EC_P256 {
80 Ok(SignatureScheme::ECDSA_NISTP256_SHA256)
81 } else if curve == OID_NIST_EC_P384 {
82 Ok(SignatureScheme::ECDSA_NISTP384_SHA384)
83 } else {
84 signature_scheme_error::UnsupportedKeySnafu.fail()
85 }
86}
87
88pub(crate) fn verify(
89 spki: SubjectPublicKeyInfoDer,
90 scheme: SignatureScheme,
91 data: &[u8],
92 signature: &[u8],
93) -> Result<bool, VerifyError> {
94 let algorithm: &'static dyn ring::signature::VerificationAlgorithm = match scheme {
95 SignatureScheme::ECDSA_NISTP384_SHA384 => &ring::signature::ECDSA_P384_SHA384_ASN1,
96 SignatureScheme::ECDSA_NISTP256_SHA256 => &ring::signature::ECDSA_P256_SHA256_ASN1,
97 SignatureScheme::ED25519 => &ring::signature::ED25519,
98 SignatureScheme::RSA_PSS_SHA512 => &ring::signature::RSA_PSS_2048_8192_SHA512,
99 _ => return verify_error::UnsupportedSchemeSnafu { scheme }.fail(),
100 };
101
102 let public_key = match SubjectPublicKeyInfo::from_der(spki.as_ref()) {
103 Ok((_remain, spki)) => spki.subject_public_key,
104 Err(_) => return Ok(false),
105 };
106
107 Ok(
108 ring::signature::UnparsedPublicKey::new(algorithm, public_key)
109 .verify(data, signature)
110 .is_ok(),
111 )
112}