@@ -13,17 +13,20 @@ use catalyst_types::{
1313 id_uri:: IdUri ,
1414 problem_report:: ProblemReport ,
1515} ;
16- use ed25519_dalek:: { VerifyingKey , PUBLIC_KEY_LENGTH } ;
16+ use ed25519_dalek:: { Signature , VerifyingKey , PUBLIC_KEY_LENGTH } ;
1717use pallas:: {
1818 codec:: {
1919 minicbor:: { Encode , Encoder } ,
2020 utils:: Bytes ,
2121 } ,
2222 ledger:: { addresses:: Address , primitives:: conway, traverse:: MultiEraTx } ,
2323} ;
24- use x509_cert:: Certificate ;
24+ use x509_cert:: { der :: Encode as X509Encode , Certificate as X509 } ;
2525
26- use super :: utils:: cip19:: compare_key_hash;
26+ use super :: {
27+ extract_key:: { c509_key, x509_key} ,
28+ utils:: cip19:: compare_key_hash,
29+ } ;
2730use crate :: cardano:: cip509:: {
2831 rbac:: Cip509RbacMetadata , types:: TxInputHash , C509Cert , Cip0134UriSet , LocalRefInt , RoleData ,
2932 RoleNumber , SimplePublicKeyType , X509DerCert ,
@@ -162,6 +165,134 @@ fn extract_stake_addresses(uris: Option<&Cip0134UriSet>) -> Vec<VKeyHash> {
162165 . collect ( )
163166}
164167
168+ /// Validate self-signed certificates.
169+ /// All certificates should be self-signed and support only ED25519 signature.
170+ pub fn validate_self_sign_cert ( metadata : & Cip509RbacMetadata , report : & ProblemReport ) {
171+ let context = "Cip509 self-signed certificate validation" ;
172+
173+ for ( index, cert) in metadata. c509_certs . iter ( ) . enumerate ( ) {
174+ if let C509Cert :: C509Certificate ( c) = cert {
175+ validate_c509_self_signed_cert ( c, index, report, context) ;
176+ }
177+ }
178+
179+ for ( index, cert) in metadata. x509_certs . iter ( ) . enumerate ( ) {
180+ if let X509DerCert :: X509Cert ( c) = cert {
181+ validate_x509_self_signed_cert ( c, index, report, context) ;
182+ }
183+ }
184+ }
185+
186+ /// Validate C509 certificate that it is a self-signed.
187+ fn validate_c509_self_signed_cert ( c : & C509 , index : usize , report : & ProblemReport , context : & str ) {
188+ // Self-sign certificate must be type 2
189+ if c. tbs_cert ( ) . c509_certificate_type ( ) != 2 {
190+ report. invalid_value (
191+ & format ! ( "C509 certificate type at index {index}" ) ,
192+ & c. tbs_cert ( ) . c509_certificate_type ( ) . to_string ( ) ,
193+ "Certificate must have cert type 2" ,
194+ context,
195+ ) ;
196+ return ;
197+ }
198+
199+ let pk = match c509_key ( c) {
200+ Ok ( pk) => pk,
201+ Err ( e) => {
202+ report. other (
203+ & format ! (
204+ "Failed to extract subject public key from C509 certificate at index {index}: {e:?}" ,
205+ ) ,
206+ context,
207+ ) ;
208+ return ;
209+ } ,
210+ } ;
211+
212+ let Some ( sig) = c
213+ . issuer_signature_value ( )
214+ . clone ( )
215+ . and_then ( |b| b. try_into ( ) . ok ( ) )
216+ . map ( |arr : [ u8 ; 64 ] | Signature :: from_bytes ( & arr) )
217+ else {
218+ report. conversion_error (
219+ & format ! ( "C509 issuer signature at index {index}" ) ,
220+ & format ! ( "{:?}" , c. issuer_signature_value( ) ) ,
221+ "Expected 64-byte Ed25519 signature" ,
222+ context,
223+ ) ;
224+ return ;
225+ } ;
226+
227+ // TODO(bkioshn): signature verification should be improved in c509 crate
228+ let Ok ( tbs_cbor) = c. tbs_cert ( ) . to_cbor :: < Vec < u8 > > ( ) else {
229+ report. invalid_encoding (
230+ & format ! ( "C509 TBS certificate at index {index}" ) ,
231+ "CBOR encoding" ,
232+ "Expected CBOR encoded TBS certificate" ,
233+ context,
234+ ) ;
235+ return ;
236+ } ;
237+ if pk. verify_strict ( & tbs_cbor, & sig) . is_err ( ) {
238+ report. other (
239+ & format ! ( "Cannot verify C509 certificate signature at index {index}" , ) ,
240+ context,
241+ ) ;
242+ }
243+ }
244+
245+ /// Validate X509 certificate that it is a self-signed.
246+ fn validate_x509_self_signed_cert ( c : & X509 , index : usize , report : & ProblemReport , context : & str ) {
247+ let pk = match x509_key ( c) {
248+ Ok ( pk) => pk,
249+ Err ( e) => {
250+ report. other (
251+ & format ! (
252+ "Failed to extract subject public key from X509 certificate at index {index}: {e:?}" ,
253+ ) ,
254+ context,
255+ ) ;
256+ return ;
257+ } ,
258+ } ;
259+
260+ let Some ( sig) = c
261+ . signature
262+ . as_bytes ( )
263+ . and_then ( |b| b. try_into ( ) . ok ( ) )
264+ . map ( |arr : [ u8 ; 64 ] | Signature :: from_bytes ( & arr) )
265+ else {
266+ report. conversion_error (
267+ & format ! ( "X509 signature at index {index}" ) ,
268+ & format ! ( "{:?}" , c. signature. as_bytes( ) ) ,
269+ "Expected 64-byte Ed25519 signature" ,
270+ context,
271+ ) ;
272+ return ;
273+ } ;
274+
275+ let tbs_der = match c. tbs_certificate . to_der ( ) {
276+ Ok ( tbs_der) => tbs_der,
277+ Err ( e) => {
278+ report. invalid_encoding (
279+ & format ! ( "X509 tbs certificate at index {index}" ) ,
280+ "DER encoding" ,
281+ & format ! ( "Expected DER encoded X509 certificate: {e:?}" ) ,
282+ context,
283+ ) ;
284+ return ;
285+ } ,
286+ } ;
287+
288+ if pk. verify_strict ( & tbs_der, & sig) . is_err ( ) {
289+ report. other (
290+ & format ! ( "Cannot verify X509 certificate signature at index {index} " ) ,
291+ context,
292+ ) ;
293+ }
294+ }
295+
165296/// Checks the role data.
166297#[ allow( clippy:: similar_names) ]
167298pub fn validate_role_data (
@@ -343,9 +474,7 @@ fn validate_role_0(
343474}
344475
345476/// Extracts `VerifyingKey` from the given `X509` certificate.
346- fn x509_cert_key (
347- cert : & Certificate , context : & str , report : & ProblemReport ,
348- ) -> Option < VerifyingKey > {
477+ fn x509_cert_key ( cert : & X509 , context : & str , report : & ProblemReport ) -> Option < VerifyingKey > {
349478 let Some ( extended_public_key) = cert
350479 . tbs_certificate
351480 . subject_public_key_info
0 commit comments