1use std::fs;
2use std::path::Path;
3
4use openssl::asn1::Asn1Time;
5use openssl::x509::{X509NameRef, X509};
6use rsa::{
7 pkcs1::DecodeRsaPrivateKey,
8 pkcs1v15::{Signature as RsaPkcs1v15Signature, SigningKey, VerifyingKey},
9 pkcs8::DecodePrivateKey,
10 RsaPrivateKey, RsaPublicKey,
11};
12use sha2::{Digest, Sha256};
13use signature::{SignatureEncoding, Signer, Verifier};
14
15use crate::core::{ErrorKind, XmlError, XmlResult};
16
17use super::base64::decode_standard_base64;
18use super::validation_data::StaticValidationDataProvider;
19use super::SignatureAlgorithm;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Pkcs12Credential {
29 private_key_der: Vec<u8>,
30 certificate_der: Vec<u8>,
31 certificate_chain_der: Vec<Vec<u8>>,
32}
33
34impl Pkcs12Credential {
35 pub fn from_file(path: impl AsRef<Path>, password: &str) -> XmlResult<Self> {
36 let path = path.as_ref();
37 let pkcs12_der = read_file_bytes(path, "cannot read PKCS#12/PFX file")?;
38 Self::from_der(&pkcs12_der, password)
39 }
40
41 pub fn from_der(pkcs12_der: &[u8], password: &str) -> XmlResult<Self> {
42 let pfx = openssl::pkcs12::Pkcs12::from_der(pkcs12_der)
43 .map_err(|error| credential_error("invalid PKCS#12/PFX DER", error))?;
44 let parsed = pfx
45 .parse2(password)
46 .map_err(|error| credential_error("cannot decrypt PKCS#12/PFX", error))?;
47 let private_key = parsed.pkey.ok_or_else(|| {
48 XmlError::new(
49 ErrorKind::Signature,
50 "PKCS#12/PFX does not contain a private key",
51 )
52 })?;
53 let certificate = parsed.cert.ok_or_else(|| {
54 XmlError::new(
55 ErrorKind::Signature,
56 "PKCS#12/PFX does not contain an X.509 certificate",
57 )
58 })?;
59
60 let private_key_der = private_key
61 .private_key_to_der()
62 .map_err(|error| credential_error("cannot export PKCS#12/PFX private key", error))?;
63 let certificate_der = certificate
64 .to_der()
65 .map_err(|error| credential_error("cannot export PKCS#12/PFX certificate", error))?;
66 let mut certificate_chain_der = vec![certificate_der.clone()];
67 if let Some(ca) = parsed.ca {
68 for certificate in ca {
69 certificate_chain_der.push(certificate.to_der().map_err(|error| {
70 credential_error("cannot export PKCS#12/PFX CA certificate", error)
71 })?);
72 }
73 }
74
75 Ok(Self {
76 private_key_der,
77 certificate_der,
78 certificate_chain_der,
79 })
80 }
81
82 pub fn private_key_der(&self) -> &[u8] {
83 &self.private_key_der
84 }
85
86 pub fn certificate_der(&self) -> &[u8] {
87 &self.certificate_der
88 }
89
90 pub fn certificate_chain_der(&self) -> &[Vec<u8>] {
91 &self.certificate_chain_der
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct CertificateDetails {
102 der: Vec<u8>,
103 issuer_name: Option<String>,
104 serial_number: Option<String>,
105}
106
107impl CertificateDetails {
108 pub fn new(der: impl Into<Vec<u8>>) -> Self {
109 Self {
110 der: der.into(),
111 issuer_name: None,
112 serial_number: None,
113 }
114 }
115
116 pub fn with_issuer_serial(
117 mut self,
118 issuer_name: impl Into<String>,
119 serial_number: impl Into<String>,
120 ) -> Self {
121 self.issuer_name = Some(issuer_name.into());
122 self.serial_number = Some(serial_number.into());
123 self
124 }
125
126 pub fn der(&self) -> &[u8] {
127 &self.der
128 }
129
130 pub fn issuer_name(&self) -> Option<&str> {
131 self.issuer_name.as_deref()
132 }
133
134 pub fn serial_number(&self) -> Option<&str> {
135 self.serial_number.as_deref()
136 }
137
138 pub fn issuer_serial(&self) -> Option<(&str, &str)> {
139 Some((self.issuer_name()?, self.serial_number()?))
140 }
141}
142
143pub trait SigningProvider {
145 fn certificate_der(&self) -> XmlResult<Vec<u8>>;
146
147 fn certificate_details(&self) -> XmlResult<CertificateDetails> {
148 Ok(CertificateDetails::new(self.certificate_der()?))
149 }
150
151 fn certificate_chain_der(&self) -> XmlResult<Vec<Vec<u8>>> {
152 Ok(vec![self.certificate_der()?])
153 }
154
155 fn certificate_chain_details(&self) -> XmlResult<Vec<CertificateDetails>> {
156 Ok(self
157 .certificate_chain_der()?
158 .into_iter()
159 .map(CertificateDetails::new)
160 .collect())
161 }
162
163 fn ensure_certificate_valid_at(&self, _unix_timestamp: i64) -> XmlResult<()> {
169 Ok(())
170 }
171
172 fn sign(&self, algorithm: SignatureAlgorithm, data: &[u8]) -> XmlResult<Vec<u8>>;
173
174 fn verify(
175 &self,
176 algorithm: SignatureAlgorithm,
177 data: &[u8],
178 signature: &[u8],
179 ) -> XmlResult<bool> {
180 Ok(self.sign(algorithm, data)? == signature)
181 }
182}
183
184#[derive(Debug, Clone)]
191pub struct RsaSha256SigningProvider {
192 private_key: RsaPrivateKey,
193 public_key: RsaPublicKey,
194 certificate_details: CertificateDetails,
195 certificate_chain_details: Vec<CertificateDetails>,
196}
197
198impl RsaSha256SigningProvider {
199 pub fn from_private_key(
200 private_key: RsaPrivateKey,
201 certificate_der: impl Into<Vec<u8>>,
202 ) -> Self {
203 let public_key = RsaPublicKey::from(&private_key);
204 Self::from_key_pair(private_key, public_key, certificate_der)
205 }
206
207 pub fn from_key_pair(
208 private_key: RsaPrivateKey,
209 public_key: RsaPublicKey,
210 certificate_der: impl Into<Vec<u8>>,
211 ) -> Self {
212 Self {
213 private_key,
214 public_key,
215 certificate_details: CertificateDetails::new(certificate_der),
216 certificate_chain_details: Vec::new(),
217 }
218 }
219
220 pub fn from_private_key_der(
221 private_key_der: &[u8],
222 certificate_der: impl Into<Vec<u8>>,
223 ) -> XmlResult<Self> {
224 let private_key = RsaPrivateKey::from_pkcs8_der(private_key_der)
225 .or_else(|_| RsaPrivateKey::from_pkcs1_der(private_key_der))
226 .map_err(|error| credential_error("invalid RSA private key DER", error))?;
227
228 Ok(Self::from_private_key(private_key, certificate_der))
229 }
230
231 pub fn from_private_key_pem(
232 private_key_pem: &str,
233 certificate_der: impl Into<Vec<u8>>,
234 ) -> XmlResult<Self> {
235 let private_key = RsaPrivateKey::from_pkcs8_pem(private_key_pem)
236 .or_else(|_| RsaPrivateKey::from_pkcs1_pem(private_key_pem))
237 .map_err(|error| credential_error("invalid RSA private key PEM", error))?;
238
239 Ok(Self::from_private_key(private_key, certificate_der))
240 }
241
242 pub fn from_pkcs12_der(pkcs12_der: &[u8], password: &str) -> XmlResult<Self> {
243 let credential = Pkcs12Credential::from_der(pkcs12_der, password)?;
244 let provider = Self::from_private_key_der(
245 credential.private_key_der(),
246 credential.certificate_der().to_vec(),
247 )?;
248 Ok(provider.with_certificate_chain_der(credential.certificate_chain_der().to_vec()))
249 }
250
251 pub fn from_pkcs12_file(path: impl AsRef<Path>, password: &str) -> XmlResult<Self> {
252 Ok(Pkcs12SigningCredentials::from_file(path, password)?.into_provider())
253 }
254
255 pub fn with_certificate_details(mut self, certificate_details: CertificateDetails) -> Self {
256 if self
257 .certificate_chain_details
258 .first()
259 .is_some_and(|first| first.der() == self.certificate_details.der())
260 {
261 self.certificate_chain_details[0] = certificate_details.clone();
262 }
263 self.certificate_details = certificate_details;
264 self
265 }
266
267 pub fn with_certificate_issuer_serial(
268 self,
269 issuer_name: impl Into<String>,
270 serial_number: impl Into<String>,
271 ) -> Self {
272 let certificate_details = self
273 .certificate_details
274 .clone()
275 .with_issuer_serial(issuer_name, serial_number);
276 self.with_certificate_details(certificate_details)
277 }
278
279 pub fn with_certificate_chain_der(mut self, certificate_chain_der: Vec<Vec<u8>>) -> Self {
280 self.certificate_chain_details = certificate_chain_der
281 .into_iter()
282 .map(CertificateDetails::new)
283 .collect();
284 self
285 }
286
287 pub fn with_certificate_chain_details(
288 mut self,
289 certificate_chain_details: Vec<CertificateDetails>,
290 ) -> Self {
291 self.certificate_chain_details = certificate_chain_details;
292 self
293 }
294
295 pub fn public_key(&self) -> &RsaPublicKey {
296 &self.public_key
297 }
298}
299
300impl SigningProvider for RsaSha256SigningProvider {
301 fn certificate_der(&self) -> XmlResult<Vec<u8>> {
302 Ok(self.certificate_details.der.clone())
303 }
304
305 fn certificate_details(&self) -> XmlResult<CertificateDetails> {
306 Ok(self.certificate_details.clone())
307 }
308
309 fn certificate_chain_der(&self) -> XmlResult<Vec<Vec<u8>>> {
310 if self.certificate_chain_details.is_empty() {
311 Ok(vec![self.certificate_details.der.clone()])
312 } else {
313 Ok(self
314 .certificate_chain_details
315 .iter()
316 .map(|certificate| certificate.der.clone())
317 .collect())
318 }
319 }
320
321 fn certificate_chain_details(&self) -> XmlResult<Vec<CertificateDetails>> {
322 if self.certificate_chain_details.is_empty() {
323 Ok(vec![self.certificate_details.clone()])
324 } else {
325 Ok(self.certificate_chain_details.clone())
326 }
327 }
328
329 fn ensure_certificate_valid_at(&self, unix_timestamp: i64) -> XmlResult<()> {
330 ensure_certificate_der_valid_at(self.certificate_details.der(), unix_timestamp)
331 }
332
333 fn sign(&self, algorithm: SignatureAlgorithm, data: &[u8]) -> XmlResult<Vec<u8>> {
334 algorithm.ensure_allowed_for_generation()?;
335
336 match algorithm {
337 SignatureAlgorithm::RsaSha256 => {
338 let signing_key = SigningKey::<Sha256>::new(self.private_key.clone());
339 Ok(signing_key.sign(data).to_vec())
340 }
341 SignatureAlgorithm::RsaSha1 => Err(XmlError::new(
342 ErrorKind::Signature,
343 "RSA-SHA1 signatures are not allowed for generation",
344 )),
345 }
346 }
347
348 fn verify(
349 &self,
350 algorithm: SignatureAlgorithm,
351 data: &[u8],
352 signature: &[u8],
353 ) -> XmlResult<bool> {
354 match algorithm {
355 SignatureAlgorithm::RsaSha256 => {
356 let signature = RsaPkcs1v15Signature::try_from(signature).map_err(|error| {
357 credential_error("invalid RSA-SHA256 signature value", error)
358 })?;
359 let verifying_key = VerifyingKey::<Sha256>::new(self.public_key.clone());
360
361 Ok(verifying_key.verify(data, &signature).is_ok())
362 }
363 SignatureAlgorithm::RsaSha1 => Ok(false),
364 }
365 }
366}
367
368#[derive(Debug, Clone)]
373pub struct Pkcs12SigningCredentials {
374 provider: RsaSha256SigningProvider,
375 certificate_details: CertificateDetails,
376 additional_certificate_der: Vec<Vec<u8>>,
377}
378
379impl Pkcs12SigningCredentials {
380 pub fn from_file(path: impl AsRef<Path>, password: &str) -> XmlResult<Self> {
381 Self::from_credential(Pkcs12Credential::from_file(path, password)?)
382 }
383
384 pub fn from_der(pkcs12_der: &[u8], password: &str) -> XmlResult<Self> {
385 Self::from_credential(Pkcs12Credential::from_der(pkcs12_der, password)?)
386 }
387
388 pub fn from_credential(credential: Pkcs12Credential) -> XmlResult<Self> {
389 let certificate_details = certificate_details_from_der(credential.certificate_der())?;
390 let provider = RsaSha256SigningProvider::from_private_key_der(
391 credential.private_key_der(),
392 credential.certificate_der().to_vec(),
393 )?
394 .with_certificate_details(certificate_details.clone());
395 let additional_certificate_der = credential
396 .certificate_chain_der()
397 .iter()
398 .skip(1)
399 .cloned()
400 .collect();
401
402 Ok(Self {
403 provider,
404 certificate_details,
405 additional_certificate_der,
406 }
407 .with_refreshed_chain())
408 }
409
410 pub fn with_issuer_serial(
411 mut self,
412 issuer_name: impl Into<String>,
413 serial_number: impl Into<String>,
414 ) -> Self {
415 self.certificate_details = self
416 .certificate_details
417 .clone()
418 .with_issuer_serial(issuer_name, serial_number);
419 self.provider = self
420 .provider
421 .clone()
422 .with_certificate_details(self.certificate_details.clone());
423 self.with_refreshed_chain()
424 }
425
426 pub fn with_certificate_details(mut self, certificate_details: CertificateDetails) -> Self {
427 self.certificate_details = certificate_details;
428 self.provider = self
429 .provider
430 .clone()
431 .with_certificate_details(self.certificate_details.clone());
432 self.with_refreshed_chain()
433 }
434
435 pub fn with_additional_certificate_der(mut self, certificate_der: impl Into<Vec<u8>>) -> Self {
436 self.additional_certificate_der.push(certificate_der.into());
437 self.with_refreshed_chain()
438 }
439
440 pub fn with_additional_certificate_file(self, path: impl AsRef<Path>) -> XmlResult<Self> {
441 Ok(self.with_additional_certificate_der(read_certificate_der_file(path)?))
442 }
443
444 pub fn with_additional_certificate_files<I, P>(mut self, paths: I) -> XmlResult<Self>
445 where
446 I: IntoIterator<Item = P>,
447 P: AsRef<Path>,
448 {
449 for path in paths {
450 self = self.with_additional_certificate_file(path)?;
451 }
452 Ok(self)
453 }
454
455 pub fn provider(&self) -> &RsaSha256SigningProvider {
456 &self.provider
457 }
458
459 pub fn certificate_details(&self) -> &CertificateDetails {
460 &self.certificate_details
461 }
462
463 pub fn certificate_der(&self) -> &[u8] {
464 self.certificate_details.der()
465 }
466
467 pub fn additional_certificate_der(&self) -> &[Vec<u8>] {
468 &self.additional_certificate_der
469 }
470
471 pub fn has_additional_certificate_chain(&self) -> bool {
472 !self.additional_certificate_der.is_empty()
473 }
474
475 pub fn validation_data_provider(&self) -> StaticValidationDataProvider {
476 let mut provider =
477 StaticValidationDataProvider::new().with_certificate(self.certificate_der().to_vec());
478 for certificate in &self.additional_certificate_der {
479 provider = provider.with_certificate(certificate.clone());
480 }
481 provider
482 }
483
484 pub fn into_provider(self) -> RsaSha256SigningProvider {
485 self.provider
486 }
487
488 fn with_refreshed_chain(mut self) -> Self {
489 let chain = if self.additional_certificate_der.is_empty() {
490 Vec::new()
491 } else {
492 let mut chain = Vec::with_capacity(self.additional_certificate_der.len() + 1);
493 chain.push(self.certificate_details.clone());
494 chain.extend(
495 self.additional_certificate_der
496 .iter()
497 .cloned()
498 .map(CertificateDetails::new),
499 );
500 chain
501 };
502 self.provider = self.provider.clone().with_certificate_chain_details(chain);
503 self
504 }
505}
506
507impl SigningProvider for Pkcs12SigningCredentials {
508 fn certificate_der(&self) -> XmlResult<Vec<u8>> {
509 self.provider.certificate_der()
510 }
511
512 fn certificate_details(&self) -> XmlResult<CertificateDetails> {
513 self.provider.certificate_details()
514 }
515
516 fn certificate_chain_der(&self) -> XmlResult<Vec<Vec<u8>>> {
517 self.provider.certificate_chain_der()
518 }
519
520 fn certificate_chain_details(&self) -> XmlResult<Vec<CertificateDetails>> {
521 self.provider.certificate_chain_details()
522 }
523
524 fn ensure_certificate_valid_at(&self, unix_timestamp: i64) -> XmlResult<()> {
525 self.provider.ensure_certificate_valid_at(unix_timestamp)
526 }
527
528 fn sign(&self, algorithm: SignatureAlgorithm, data: &[u8]) -> XmlResult<Vec<u8>> {
529 self.provider.sign(algorithm, data)
530 }
531
532 fn verify(
533 &self,
534 algorithm: SignatureAlgorithm,
535 data: &[u8],
536 signature: &[u8],
537 ) -> XmlResult<bool> {
538 self.provider.verify(algorithm, data, signature)
539 }
540}
541
542#[derive(Debug, Clone, PartialEq, Eq)]
548pub struct DeterministicSigningProvider {
549 certificate_details: CertificateDetails,
550 certificate_chain_details: Vec<CertificateDetails>,
551 secret: Vec<u8>,
552}
553
554impl DeterministicSigningProvider {
555 pub fn new(certificate_der: impl Into<Vec<u8>>, secret: impl Into<Vec<u8>>) -> Self {
556 Self {
557 certificate_details: CertificateDetails::new(certificate_der),
558 certificate_chain_details: Vec::new(),
559 secret: secret.into(),
560 }
561 }
562
563 pub fn with_certificate_issuer_serial(
564 self,
565 issuer_name: impl Into<String>,
566 serial_number: impl Into<String>,
567 ) -> Self {
568 let certificate_details = self
569 .certificate_details
570 .clone()
571 .with_issuer_serial(issuer_name, serial_number);
572 Self {
573 certificate_details,
574 ..self
575 }
576 }
577
578 pub fn with_certificate_chain_details(
579 mut self,
580 certificate_chain_details: Vec<CertificateDetails>,
581 ) -> Self {
582 self.certificate_chain_details = certificate_chain_details;
583 self
584 }
585}
586
587impl SigningProvider for DeterministicSigningProvider {
588 fn certificate_der(&self) -> XmlResult<Vec<u8>> {
589 Ok(self.certificate_details.der.clone())
590 }
591
592 fn certificate_details(&self) -> XmlResult<CertificateDetails> {
593 Ok(self.certificate_details.clone())
594 }
595
596 fn certificate_chain_der(&self) -> XmlResult<Vec<Vec<u8>>> {
597 if self.certificate_chain_details.is_empty() {
598 Ok(vec![self.certificate_details.der.clone()])
599 } else {
600 Ok(self
601 .certificate_chain_details
602 .iter()
603 .map(|certificate| certificate.der.clone())
604 .collect())
605 }
606 }
607
608 fn certificate_chain_details(&self) -> XmlResult<Vec<CertificateDetails>> {
609 if self.certificate_chain_details.is_empty() {
610 Ok(vec![self.certificate_details.clone()])
611 } else {
612 Ok(self.certificate_chain_details.clone())
613 }
614 }
615
616 fn sign(&self, algorithm: SignatureAlgorithm, data: &[u8]) -> XmlResult<Vec<u8>> {
617 algorithm.ensure_allowed_for_generation()?;
618
619 let mut hasher = Sha256::new();
620 hasher.update(algorithm.uri().as_bytes());
621 hasher.update([0]);
622 hasher.update(&self.secret);
623 hasher.update([0]);
624 hasher.update(self.certificate_details.der());
625 hasher.update([0]);
626 hasher.update(data);
627 Ok(hasher.finalize().to_vec())
628 }
629}
630
631fn credential_error(context: &str, error: impl std::fmt::Display) -> XmlError {
632 XmlError::new(ErrorKind::Signature, format!("{context}: {error}"))
633}
634
635fn ensure_certificate_der_valid_at(certificate_der: &[u8], unix_timestamp: i64) -> XmlResult<()> {
636 let certificate = X509::from_der(certificate_der)
637 .map_err(|error| credential_error("invalid X.509 certificate DER", error))?;
638 let signing_time = Asn1Time::from_unix(unix_timestamp as _)
639 .map_err(|error| credential_error("invalid certificate validation time", error))?;
640 let not_before = certificate.not_before();
641 let not_after = certificate.not_after();
642
643 if not_before
644 .compare(&signing_time)
645 .map_err(|error| credential_error("cannot compare certificate NotBefore", error))?
646 == std::cmp::Ordering::Greater
647 {
648 return Err(XmlError::new(
649 ErrorKind::Signature,
650 format!(
651 "XAdES SigningTime is before certificate NotBefore: signing_time={}, not_before={}",
652 signing_time.as_ref(),
653 not_before
654 ),
655 ));
656 }
657
658 if not_after
659 .compare(&signing_time)
660 .map_err(|error| credential_error("cannot compare certificate NotAfter", error))?
661 == std::cmp::Ordering::Less
662 {
663 return Err(XmlError::new(
664 ErrorKind::Signature,
665 format!(
666 "XAdES SigningTime is after certificate NotAfter: signing_time={}, not_after={}",
667 signing_time.as_ref(),
668 not_after
669 ),
670 ));
671 }
672
673 Ok(())
674}
675
676fn certificate_details_from_der(certificate_der: &[u8]) -> XmlResult<CertificateDetails> {
677 let certificate = X509::from_der(certificate_der)
678 .map_err(|error| credential_error("invalid X.509 certificate DER", error))?;
679 let issuer_name = x509_name_to_rfc4514_like_string(certificate.issuer_name())?;
680 let serial_number = certificate
681 .serial_number()
682 .to_bn()
683 .map_err(|error| credential_error("cannot read X.509 certificate serial", error))?
684 .to_dec_str()
685 .map_err(|error| credential_error("cannot format X.509 certificate serial", error))?
686 .to_string();
687
688 Ok(CertificateDetails::new(certificate_der.to_vec())
689 .with_issuer_serial(issuer_name, serial_number))
690}
691
692fn x509_name_to_rfc4514_like_string(name: &X509NameRef) -> XmlResult<String> {
693 let mut parts = Vec::new();
694
695 for entry in name.entries() {
696 let key = entry
697 .object()
698 .nid()
699 .short_name()
700 .map_err(|error| credential_error("cannot read X.509 name attribute", error))?;
701 let value = entry
702 .data()
703 .as_utf8()
704 .map_err(|error| credential_error("cannot read X.509 name value", error))?
705 .to_string();
706 parts.push(format!(
707 "{key}={}",
708 escape_x509_name_value_for_rfc4514(&value)
709 ));
710 }
711
712 Ok(parts.join(","))
713}
714
715fn escape_x509_name_value_for_rfc4514(value: &str) -> String {
716 let chars: Vec<char> = value.chars().collect();
717 let mut escaped = String::new();
718
719 for (index, ch) in chars.iter().copied().enumerate() {
720 let is_first = index == 0;
721 let is_last = index + 1 == chars.len();
722 if matches!(ch, ',' | '+' | '"' | '\\' | '<' | '>' | ';')
723 || (is_first && (ch == ' ' || ch == '#'))
724 || (is_last && ch == ' ')
725 {
726 escaped.push('\\');
727 }
728 escaped.push(ch);
729 }
730
731 escaped
732}
733
734fn read_file_bytes(path: &Path, context: &str) -> XmlResult<Vec<u8>> {
735 fs::read(path).map_err(|error| {
736 XmlError::new(
737 ErrorKind::Signature,
738 format!("{context} `{}`: {error}", path.display()),
739 )
740 })
741}
742
743fn read_certificate_der_file(path: impl AsRef<Path>) -> XmlResult<Vec<u8>> {
744 let path = path.as_ref();
745 certificate_der_from_pem_or_der(read_file_bytes(path, "cannot read certificate file")?)
746}
747
748fn certificate_der_from_pem_or_der(bytes: Vec<u8>) -> XmlResult<Vec<u8>> {
749 if let Ok(text) = std::str::from_utf8(&bytes) {
750 if text.contains("-----BEGIN CERTIFICATE-----") {
751 return decode_pem_block(text, "CERTIFICATE");
752 }
753 }
754 Ok(bytes)
755}
756
757fn decode_pem_block(text: &str, label: &str) -> XmlResult<Vec<u8>> {
758 let begin = format!("-----BEGIN {label}-----");
759 let end = format!("-----END {label}-----");
760 let start = text
761 .find(&begin)
762 .ok_or_else(|| XmlError::new(ErrorKind::Signature, "missing PEM begin marker"))?
763 + begin.len();
764 let finish = text[start..]
765 .find(&end)
766 .ok_or_else(|| XmlError::new(ErrorKind::Signature, "missing PEM end marker"))?
767 + start;
768 let encoded: String = text[start..finish]
769 .chars()
770 .filter(|ch| !ch.is_whitespace())
771 .collect();
772 decode_standard_base64(&encoded)
773}
774
775#[cfg(test)]
776mod tests {
777 use std::fs;
778
779 use crate::parser::parse_str;
780 use crate::signature::{
781 sign_enveloped, sign_xades_bes_enveloped, verify_enveloped, verify_xades_bes_enveloped,
782 XadesConfig, XadesValidationDataProvider, XmlDsigConfig,
783 };
784 use crate::writer::to_string_compact;
785 use openssl::asn1::Asn1Time;
786 use openssl::bn::BigNum;
787 use openssl::hash::MessageDigest;
788 use openssl::pkcs12::Pkcs12;
789 use openssl::pkey::PKey;
790 use openssl::x509::{X509NameBuilder, X509};
791
792 use super::*;
793
794 const RSA_PRIVATE_KEY_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
795MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDhxyLXp0r/ySjk
796ZRA/uP+qvy3PtpmHBawMcqhqkcTULTA0VN09cISj/9NUQeDooamqIDQQwGuK30R/
797MW/23gkDuyrtzeouICJafWNIj1g0QBuq351pais4DKl8sRj9lSp1Vl5EVDAlfw6D
798k/I/i5XGOauH61CST7IB2WqVppMbNq7j6nEYor21E3/rRE0pqrhPAPfeGskqOJQ9
799NhaaeQt0EPqc9tnlws6ZHo44nTlegYv83/kWV9HOX1l6GmF7QMTzmi6wnkmojKKh
800wM5tGEv1VG/5owv7IDneeouK+oosg3aX2B6aMbxnLoQpgjUPjXVP6O1Oo/H4ucua
8014nQ+vaJXAgMBAAECggEAToM3RJLya7yCMdpLKj2k+rV8ssym2uNIDxQYKOcD8Vy9
802dJVGUkU8euNNk/FMytjc7UJBmMmxHBvD8A87Bjf0Ho4JwaRnmR6nk5wi2Gqwm4rn
803lCYq0SuQV+9fSPM044npt+AO6+fyzjc+zta12Q8rSEFputxDqn14Q1hdziic40sb
804Zk2+t8tYe1ntFVAW+rp5RktW1o/9B/+pi/PrOb8lP9c5eoK5HIfDxm6aC1b6uEvk
805FhBEGDC04TENR7qWpmXDgGUANQC9WvvnhYOO/7S+J1NyCT2WPcTQtKudJ4PiBfuS
806mr2OklkmXLQi6Kydol+Ri1pfX1UZZ/l9eGKmhV2t0QKBgQD77ofCY0yfs1WVIfsy
807OjE9p70mt3b52AwCPVLap5AO9W6lPVJkUmHMaeixHu9MnW3u59bdbpc3JUNct29r
8083aWziZ9ezyMgtrdDnOJn9d/mI+tlXcVTkRbnKtyx/JbQab3GyCN8brhYcZtaLIoc
809JM5tBWCBEKQZEfzQ0YE40lEFowKBgQDlbHzBBfdUgGDKa9vZjNregY9hP7mg/wrJ
810XC8Wrnl59McHMeY+c9lsPoFpVW1sncaSyxLVguYtf9zOw4Xi4/EuanIlBuBXvpML
811vn49c3isrMuVnuc6s6VG0qk4Nxj2x6yhbfoJ5XkoZ1CIw1lk4sedhbtSlt6cnO1m
812bDCEAs8zvQKBgEK0+Rt+gYZzzMBtO/8jq3Ag3xPGVml3TE63gB3Hanybfg2gvBU2
813PxEKJgPoJgLKWJZ+qsT9CGsgocKGC6mrCboNQbav8CQ0XTg47TYLw5pDfovblWk4
814LLFPBxrVv/U1Wnus+MB07Lj2c+Ufj/49vK7fUps6FclRmviL0MSD49IzAoGBALTK
8152kDN78sCY8QAXT7B9hRT6uZK7oCFmz10zJLGKWpGz7TGyNc8OgFH/HlCXbmzV7GE
816IDJrNfJzCVFS2SYkVIIsVgkBszbSMlSV6CuK3HTOspwUnckvmjYGel2XZa/LSCnq
817XZkA4YpKaDduIfsTjxR+N1DtHT4zmA0Xgt/0ys3NAoGBAIyaAw4uHkcv/ukB7C61
818vNxNKlzQGmIFENaFZnV1xIybIEXRYpU/W5FJPn0mexSE7rcW21s3XhPSirez4ctV
819Rqp4dm3rUuCm0un6gc3ARoj7VKIE8EIBI6f6l12CdNd7NMDaP7uhO8RHCuC5NW4A
82075CcGa3kvBm08ghSr6XTg21R
821-----END PRIVATE KEY-----"#;
822
823 fn real_crypto_provider() -> XmlResult<RsaSha256SigningProvider> {
824 RsaSha256SigningProvider::from_private_key_pem(
825 RSA_PRIVATE_KEY_PEM,
826 b"fixture-cert-der".to_vec(),
827 )
828 }
829
830 fn pkcs12_fixture(password: &str) -> Vec<u8> {
831 let now = std::time::SystemTime::now()
832 .duration_since(std::time::UNIX_EPOCH)
833 .expect("system clock after UNIX epoch")
834 .as_secs() as i64;
835 pkcs12_fixture_with_validity(password, now, now + 30 * 86_400)
836 }
837
838 fn pkcs12_fixture_with_validity(
839 password: &str,
840 not_before_unix: i64,
841 not_after_unix: i64,
842 ) -> Vec<u8> {
843 let pkey = PKey::private_key_from_pem(RSA_PRIVATE_KEY_PEM.as_bytes()).expect("fixture key");
844 let mut name = X509NameBuilder::new().expect("x509 name builder");
845 name.append_entry_by_text("CN", "xdoc test")
846 .expect("x509 cn");
847 let name = name.build();
848
849 let mut certificate = X509::builder().expect("x509 builder");
850 let serial = BigNum::from_dec_str("42")
851 .expect("serial")
852 .to_asn1_integer()
853 .expect("asn1 serial");
854 certificate.set_version(2).expect("x509 version");
855 certificate.set_serial_number(&serial).expect("x509 serial");
856 certificate.set_subject_name(&name).expect("x509 subject");
857 certificate.set_issuer_name(&name).expect("x509 issuer");
858 certificate.set_pubkey(&pkey).expect("x509 public key");
859 certificate
860 .set_not_before(
861 Asn1Time::from_unix(not_before_unix as _)
862 .expect("not before")
863 .as_ref(),
864 )
865 .expect("x509 not before");
866 certificate
867 .set_not_after(
868 Asn1Time::from_unix(not_after_unix as _)
869 .expect("not after")
870 .as_ref(),
871 )
872 .expect("x509 not after");
873 certificate
874 .sign(&pkey, MessageDigest::sha256())
875 .expect("x509 sign");
876 let certificate = certificate.build();
877
878 Pkcs12::builder()
879 .name("xdoc-test")
880 .pkey(&pkey)
881 .cert(&certificate)
882 .build2(password)
883 .expect("PFX fixture")
884 .to_der()
885 .expect("PFX DER")
886 }
887
888 fn temp_path(name: &str) -> std::path::PathBuf {
889 std::env::temp_dir().join(format!("xdoc-{name}-{}", std::process::id()))
890 }
891
892 #[test]
893 fn signature_provider_signs_deterministically() -> XmlResult<()> {
894 let provider = DeterministicSigningProvider::new(b"cert".to_vec(), b"secret".to_vec());
895
896 let first = provider.sign(SignatureAlgorithm::RsaSha256, b"payload")?;
897 let second = provider.sign(SignatureAlgorithm::RsaSha256, b"payload")?;
898
899 assert_eq!(first, second);
900 assert!(provider.verify(SignatureAlgorithm::RsaSha256, b"payload", &first)?);
901 assert!(!provider.verify(SignatureAlgorithm::RsaSha256, b"tampered", &first)?);
902
903 Ok(())
904 }
905
906 #[test]
907 fn signature_provider_rejects_legacy_generation_algorithm() {
908 let provider = DeterministicSigningProvider::new(b"cert".to_vec(), b"secret".to_vec());
909
910 assert!(provider
911 .sign(SignatureAlgorithm::RsaSha1, b"payload")
912 .is_err());
913 }
914
915 #[test]
916 fn real_crypto_provider_signs_and_verifies_rsa_sha256() -> XmlResult<()> {
917 let provider = real_crypto_provider()?;
918 let signature = provider.sign(SignatureAlgorithm::RsaSha256, b"payload")?;
919
920 assert!(provider.verify(SignatureAlgorithm::RsaSha256, b"payload", &signature)?);
921 assert!(!provider.verify(SignatureAlgorithm::RsaSha256, b"tampered", &signature)?);
922
923 Ok(())
924 }
925
926 #[test]
927 fn real_crypto_provider_rejects_invalid_pem() {
928 let error = RsaSha256SigningProvider::from_private_key_pem("not a key", b"cert".to_vec())
929 .expect_err("invalid PEM should fail");
930
931 assert_eq!(error.kind(), &ErrorKind::Signature);
932 assert!(error.message().contains("invalid RSA private key PEM"));
933 }
934
935 #[test]
936 fn real_crypto_provider_rejects_legacy_generation_algorithm() -> XmlResult<()> {
937 let provider = real_crypto_provider()?;
938
939 let error = provider
940 .sign(SignatureAlgorithm::RsaSha1, b"payload")
941 .expect_err("RSA-SHA1 should not be generated");
942
943 assert_eq!(error.kind(), &ErrorKind::Signature);
944 Ok(())
945 }
946
947 #[test]
948 fn real_crypto_provider_exposes_certificate_chain() -> XmlResult<()> {
949 let provider = real_crypto_provider()?
950 .with_certificate_chain_der(vec![b"leaf".to_vec(), b"issuer".to_vec()]);
951
952 assert_eq!(
953 provider.certificate_chain_der()?,
954 vec![b"leaf".to_vec(), b"issuer".to_vec()]
955 );
956
957 Ok(())
958 }
959
960 #[test]
961 fn pkcs12_credential_extracts_private_key_certificate_and_chain() -> XmlResult<()> {
962 let pfx = pkcs12_fixture("secret");
963 let credential = Pkcs12Credential::from_der(&pfx, "secret")?;
964
965 assert!(!credential.private_key_der().is_empty());
966 assert!(!credential.certificate_der().is_empty());
967 assert_eq!(credential.certificate_chain_der().len(), 1);
968
969 Ok(())
970 }
971
972 #[test]
973 fn pkcs12_signing_credentials_extract_x509_issuer_serial() -> XmlResult<()> {
974 let pfx = pkcs12_fixture("secret");
975 let credentials = Pkcs12SigningCredentials::from_der(&pfx, "secret")?;
976
977 assert_eq!(
978 credentials.certificate_details().issuer_serial(),
979 Some(("CN=xdoc test", "42"))
980 );
981
982 Ok(())
983 }
984
985 #[test]
986 fn pkcs12_credential_rejects_wrong_password() {
987 let pfx = pkcs12_fixture("secret");
988 let error =
989 Pkcs12Credential::from_der(&pfx, "wrong").expect_err("wrong password must fail");
990
991 assert_eq!(error.kind(), &ErrorKind::Signature);
992 assert!(error.message().contains("PKCS#12/PFX"));
993 }
994
995 #[test]
996 fn real_crypto_provider_loads_pkcs12_and_signs() -> XmlResult<()> {
997 let pfx = pkcs12_fixture("secret");
998 let provider = RsaSha256SigningProvider::from_pkcs12_der(&pfx, "secret")?;
999 let signature = provider.sign(SignatureAlgorithm::RsaSha256, b"payload")?;
1000
1001 assert!(provider.verify(SignatureAlgorithm::RsaSha256, b"payload", &signature)?);
1002 assert_eq!(provider.certificate_chain_der()?.len(), 1);
1003
1004 Ok(())
1005 }
1006
1007 #[test]
1008 fn pkcs12_signing_credentials_load_file_and_delegate_provider() -> XmlResult<()> {
1009 let path = temp_path("credential.pfx");
1010 fs::write(&path, pkcs12_fixture("secret")).expect("write PFX fixture");
1011
1012 let credentials = Pkcs12SigningCredentials::from_file(&path, "secret")?
1013 .with_additional_certificate_der(b"issuer-cert".to_vec());
1014 let signature = credentials.sign(SignatureAlgorithm::RsaSha256, b"payload")?;
1015 let validation_data = credentials.validation_data_provider();
1016
1017 assert!(credentials.verify(SignatureAlgorithm::RsaSha256, b"payload", &signature)?);
1018 assert_eq!(
1019 credentials.certificate_details().issuer_serial(),
1020 Some(("CN=xdoc test", "42"))
1021 );
1022 assert!(credentials.has_additional_certificate_chain());
1023 assert_eq!(credentials.additional_certificate_der().len(), 1);
1024 assert_eq!(credentials.certificate_chain_der()?.len(), 2);
1025 assert_eq!(validation_data.certificate_values()?.len(), 2);
1026
1027 let _ = fs::remove_file(path);
1028 Ok(())
1029 }
1030
1031 #[test]
1032 fn xades_signing_time_is_validated_against_pkcs12_certificate() -> XmlResult<()> {
1033 let signing_time = 1_800_000_000;
1034 let pfx = pkcs12_fixture_with_validity("secret", signing_time - 60, signing_time + 60);
1035 let credentials = Pkcs12SigningCredentials::from_der(&pfx, "secret")?;
1036 let document = parse_str(r#"<Root Id="doc-1"><Item>value</Item></Root>"#)?;
1037 let config = XadesConfig::new().with_signing_time_unix_timestamp(signing_time);
1038
1039 let signed = sign_xades_bes_enveloped(&document, &credentials, &config)?;
1040 let report = verify_xades_bes_enveloped(&signed, &credentials, &config)?;
1041 let xml = to_string_compact(&signed)?;
1042
1043 assert!(report.valid);
1044 assert!(xml.contains("<xades:SigningTime>2027-01-15T08:00:00Z</xades:SigningTime>"));
1045 Ok(())
1046 }
1047
1048 #[test]
1049 fn xades_signing_time_before_certificate_validity_is_rejected() -> XmlResult<()> {
1050 let signing_time = 1_800_000_000;
1051 let pfx = pkcs12_fixture_with_validity("secret", signing_time + 60, signing_time + 120);
1052 let credentials = Pkcs12SigningCredentials::from_der(&pfx, "secret")?;
1053 let document = parse_str(r#"<Root Id="doc-1"><Item>value</Item></Root>"#)?;
1054 let config = XadesConfig::new().with_signing_time_unix_timestamp(signing_time);
1055
1056 let error = sign_xades_bes_enveloped(&document, &credentials, &config)
1057 .expect_err("signing before NotBefore must fail");
1058
1059 assert_eq!(error.kind(), &ErrorKind::Signature);
1060 assert!(error.message().contains("before certificate NotBefore"));
1061 Ok(())
1062 }
1063
1064 #[test]
1065 fn xades_signing_time_after_certificate_validity_is_rejected() -> XmlResult<()> {
1066 let signing_time = 1_800_000_000;
1067 let pfx = pkcs12_fixture_with_validity("secret", signing_time - 120, signing_time - 60);
1068 let credentials = Pkcs12SigningCredentials::from_der(&pfx, "secret")?;
1069 let document = parse_str(r#"<Root Id="doc-1"><Item>value</Item></Root>"#)?;
1070 let config = XadesConfig::new().with_signing_time_unix_timestamp(signing_time);
1071
1072 let error = sign_xades_bes_enveloped(&document, &credentials, &config)
1073 .expect_err("signing after NotAfter must fail");
1074
1075 assert_eq!(error.kind(), &ErrorKind::Signature);
1076 assert!(error.message().contains("after certificate NotAfter"));
1077 Ok(())
1078 }
1079
1080 #[test]
1081 fn real_crypto_provider_signs_and_verifies_enveloped_document() -> XmlResult<()> {
1082 let document = parse_str(r#"<Root Id="doc-1"><Item>value</Item></Root>"#)?;
1083 let provider = real_crypto_provider()?;
1084
1085 let signed = sign_enveloped(&document, &provider, &XmlDsigConfig::new())?;
1086 let report = verify_enveloped(&signed, &provider, &XmlDsigConfig::new())?;
1087
1088 assert!(report.valid);
1089 assert!(report.signature_value_valid);
1090
1091 Ok(())
1092 }
1093}