1
1
use anyhow:: Context ;
2
2
use camino:: Utf8Path ;
3
3
use device_id:: DeviceIdError ;
4
- use rcgen:: Certificate ;
5
4
use rcgen:: CertificateParams ;
6
5
use rcgen:: KeyPair ;
7
6
use sha1:: Digest ;
@@ -224,17 +223,17 @@ pub struct RemoteKeyPair {
224
223
algorithm : & ' static rcgen:: SignatureAlgorithm ,
225
224
}
226
225
227
- impl RemoteKeyPair {
228
- pub fn to_key_pair ( & self ) -> Result < KeyPair , CertificateError > {
229
- Ok ( KeyPair :: from_remote ( Box :: new ( self . clone ( ) ) ) ? )
226
+ impl rcgen :: PublicKeyData for RemoteKeyPair {
227
+ fn der_bytes ( & self ) -> & [ u8 ] {
228
+ & self . public_key_raw
230
229
}
231
- }
232
230
233
- impl rcgen:: RemoteKeyPair for RemoteKeyPair {
234
- fn public_key ( & self ) -> & [ u8 ] {
235
- & self . public_key_raw
231
+ fn algorithm ( & self ) -> & ' static rcgen:: SignatureAlgorithm {
232
+ self . algorithm
236
233
}
234
+ }
237
235
236
+ impl rcgen:: SigningKey for RemoteKeyPair {
238
237
fn sign ( & self , msg : & [ u8 ] ) -> Result < Vec < u8 > , rcgen:: Error > {
239
238
// the error here is not PEM-related, but we need to return a foreign error type, and there
240
239
// are no other better variants that could let us return context, so we'll have to use this
@@ -245,14 +244,43 @@ impl rcgen::RemoteKeyPair for RemoteKeyPair {
245
244
. sign ( msg)
246
245
. map_err ( |e| rcgen:: Error :: PemError ( e. to_string ( ) ) )
247
246
}
247
+ }
248
+
249
+ pub struct KeyCertPair {
250
+ certificate : rcgen:: Certificate ,
251
+ // in rcgen 0.14 params are necessary to generate the CSR
252
+ params : rcgen:: CertificateParams ,
253
+ signing_key : SigningKeyWrapper ,
254
+ }
255
+
256
+ enum SigningKeyWrapper {
257
+ Local ( Zeroizing < rcgen:: KeyPair > ) ,
258
+ Remote ( RemoteKeyPair ) ,
259
+ }
260
+
261
+ impl rcgen:: PublicKeyData for SigningKeyWrapper {
262
+ fn der_bytes ( & self ) -> & [ u8 ] {
263
+ match self {
264
+ Self :: Local ( k) => k. der_bytes ( ) ,
265
+ Self :: Remote ( k) => k. der_bytes ( ) ,
266
+ }
267
+ }
248
268
249
269
fn algorithm ( & self ) -> & ' static rcgen:: SignatureAlgorithm {
250
- self . algorithm
270
+ match self {
271
+ Self :: Local ( k) => k. algorithm ( ) ,
272
+ Self :: Remote ( k) => k. algorithm ( ) ,
273
+ }
251
274
}
252
275
}
253
276
254
- pub struct KeyCertPair {
255
- certificate : Zeroizing < rcgen:: Certificate > ,
277
+ impl rcgen:: SigningKey for SigningKeyWrapper {
278
+ fn sign ( & self , msg : & [ u8 ] ) -> Result < Vec < u8 > , rcgen:: Error > {
279
+ match self {
280
+ Self :: Local ( k) => k. sign ( msg) ,
281
+ Self :: Remote ( k) => k. sign ( msg) ,
282
+ }
283
+ }
256
284
}
257
285
258
286
impl KeyCertPair {
@@ -263,11 +291,13 @@ impl KeyCertPair {
263
291
) -> Result < KeyCertPair , CertificateError > {
264
292
let today = OffsetDateTime :: now_utc ( ) ;
265
293
let not_before = today - Duration :: days ( 1 ) ; // Ensure the certificate is valid today
266
- let params =
294
+ let ( params, signing_key ) =
267
295
Self :: create_selfsigned_certificate_parameters ( config, id, key_kind, not_before) ?;
268
296
269
297
Ok ( KeyCertPair {
270
- certificate : Zeroizing :: new ( Certificate :: from_params ( params) ?) ,
298
+ certificate : params. self_signed ( & signing_key) ?,
299
+ signing_key,
300
+ params,
271
301
} )
272
302
}
273
303
@@ -278,11 +308,14 @@ impl KeyCertPair {
278
308
) -> Result < KeyCertPair , CertificateError > {
279
309
// Create Certificate without `not_before` and `not_after` fields
280
310
// as rcgen library will not parse it for certificate signing request
281
- let params = Self :: create_csr_parameters ( config, id, key_kind) ?;
311
+ let ( params, signing_key) = Self :: create_csr_parameters ( config, id, key_kind) ?;
312
+ let issuer = rcgen:: Issuer :: from_params ( & params, & signing_key) ;
282
313
Ok ( KeyCertPair {
283
- certificate : Zeroizing :: new (
284
- Certificate :: from_params ( params) . context ( "Failed to create CSR" ) ?,
285
- ) ,
314
+ certificate : params
315
+ . signed_by ( & signing_key, & issuer)
316
+ . context ( "Failed to create CSR" ) ?,
317
+ signing_key,
318
+ params,
286
319
} )
287
320
}
288
321
@@ -291,8 +324,8 @@ impl KeyCertPair {
291
324
id : & str ,
292
325
key_kind : & KeyKind ,
293
326
not_before : OffsetDateTime ,
294
- ) -> Result < CertificateParams , CertificateError > {
295
- let mut params = Self :: create_csr_parameters ( config, id, key_kind) ?;
327
+ ) -> Result < ( CertificateParams , SigningKeyWrapper ) , CertificateError > {
328
+ let ( mut params, signing_key ) = Self :: create_csr_parameters ( config, id, key_kind) ?;
296
329
297
330
let not_after = not_before + Duration :: days ( config. validity_period_days . into ( ) ) ;
298
331
params. not_before = not_before;
@@ -301,14 +334,14 @@ impl KeyCertPair {
301
334
// IsCa::SelfSignedOnly is rejected by C8Y with "422 Unprocessable Entity"
302
335
params. is_ca = rcgen:: IsCa :: Ca ( rcgen:: BasicConstraints :: Unconstrained ) ;
303
336
304
- Ok ( params)
337
+ Ok ( ( params, signing_key ) )
305
338
}
306
339
307
340
fn create_csr_parameters (
308
341
config : & CsrTemplate ,
309
342
id : & str ,
310
343
key_kind : & KeyKind ,
311
- ) -> Result < CertificateParams , CertificateError > {
344
+ ) -> Result < ( CertificateParams , SigningKeyWrapper ) , CertificateError > {
312
345
KeyCertPair :: check_identifier ( id, config. max_cn_size ) ?;
313
346
let mut distinguished_name = rcgen:: DistinguishedName :: new ( ) ;
314
347
distinguished_name. push ( rcgen:: DnType :: CommonName , id) ;
@@ -321,38 +354,38 @@ impl KeyCertPair {
321
354
let mut params = CertificateParams :: default ( ) ;
322
355
params. distinguished_name = distinguished_name;
323
356
324
- match key_kind {
357
+ let signing_key : SigningKeyWrapper = match key_kind {
325
358
KeyKind :: New => {
326
359
// ECDSA signing using the P-256 curves and SHA-256 hashing as per RFC 5758
327
- params. alg = & rcgen:: PKCS_ECDSA_P256_SHA256 ;
360
+ SigningKeyWrapper :: Local ( Zeroizing :: new ( KeyPair :: generate_for (
361
+ & rcgen:: PKCS_ECDSA_P256_SHA256 ,
362
+ ) ?) )
328
363
}
329
364
KeyKind :: Reuse { keypair_pem } => {
330
365
// Use the same signing algorithm as the existing key
331
366
// Failing to do so leads to an error telling the algorithm is not compatible
332
- let key_pair = KeyPair :: from_pem ( keypair_pem) ?;
333
- params. alg = key_pair. algorithm ( ) ;
334
- params. key_pair = Some ( key_pair) ;
335
- }
336
- KeyKind :: ReuseRemote ( key_pair) => {
337
- let key_pair = key_pair. to_key_pair ( ) ?;
338
- params. alg = key_pair. algorithm ( ) ;
339
- params. key_pair = Some ( key_pair)
367
+ SigningKeyWrapper :: Local ( Zeroizing :: new ( KeyPair :: from_pem ( keypair_pem) ?) )
340
368
}
341
- }
369
+ KeyKind :: ReuseRemote ( remote) => SigningKeyWrapper :: Remote ( remote. clone ( ) ) ,
370
+ } ;
342
371
343
- Ok ( params)
372
+ Ok ( ( params, signing_key ) )
344
373
}
345
374
346
375
pub fn certificate_pem_string ( & self ) -> Result < String , CertificateError > {
347
- Ok ( self . certificate . serialize_pem ( ) ? )
376
+ Ok ( self . certificate . pem ( ) )
348
377
}
349
378
350
379
pub fn private_key_pem_string ( & self ) -> Result < Zeroizing < String > , CertificateError > {
351
- Ok ( Zeroizing :: new ( self . certificate . serialize_private_key_pem ( ) ) )
380
+ if let SigningKeyWrapper :: Local ( keypair) = & self . signing_key {
381
+ Ok ( Zeroizing :: new ( keypair. serialize_pem ( ) ) )
382
+ } else {
383
+ Err ( anyhow:: anyhow!( "Can't serialize private key PEM for remote private key" ) . into ( ) )
384
+ }
352
385
}
353
386
354
387
pub fn certificate_signing_request_string ( & self ) -> Result < String , CertificateError > {
355
- Ok ( self . certificate . serialize_request_pem ( ) ?)
388
+ Ok ( self . params . serialize_request ( & self . signing_key ) ? . pem ( ) ?)
356
389
}
357
390
358
391
fn check_identifier ( id : & str , max_cn_size : usize ) -> Result < ( ) , CertificateError > {
@@ -555,7 +588,7 @@ mod tests {
555
588
let id = "some-id" ;
556
589
let birthdate = datetime ! ( 2021 -03 -31 16 : 39 : 57 +01 : 00 ) ;
557
590
558
- let params = KeyCertPair :: create_selfsigned_certificate_parameters (
591
+ let ( params, signing_key ) = KeyCertPair :: create_selfsigned_certificate_parameters (
559
592
& config,
560
593
id,
561
594
& KeyKind :: New ,
@@ -564,9 +597,11 @@ mod tests {
564
597
. expect ( "Fail to get a certificate parameters" ) ;
565
598
566
599
let keypair = KeyCertPair {
567
- certificate : Zeroizing :: new (
568
- Certificate :: from_params ( params) . expect ( "Fail to create a certificate" ) ,
569
- ) ,
600
+ certificate : params
601
+ . self_signed ( & signing_key)
602
+ . expect ( "Fail to create a certificate" ) ,
603
+ params,
604
+ signing_key,
570
605
} ;
571
606
572
607
// Check the not_before date
@@ -587,7 +622,7 @@ mod tests {
587
622
let id = "some-id" ;
588
623
let birthdate = datetime ! ( 2021 -03 -31 16 : 39 : 57 +01 : 00 ) ;
589
624
590
- let params = KeyCertPair :: create_selfsigned_certificate_parameters (
625
+ let ( params, signing_key ) = KeyCertPair :: create_selfsigned_certificate_parameters (
591
626
& config,
592
627
id,
593
628
& KeyKind :: New ,
@@ -596,9 +631,11 @@ mod tests {
596
631
. expect ( "Fail to get a certificate parameters" ) ;
597
632
598
633
let keypair = KeyCertPair {
599
- certificate : Zeroizing :: new (
600
- Certificate :: from_params ( params) . expect ( "Fail to create a certificate" ) ,
601
- ) ,
634
+ certificate : params
635
+ . self_signed ( & signing_key)
636
+ . expect ( "Fail to create a certificate" ) ,
637
+ params,
638
+ signing_key,
602
639
} ;
603
640
604
641
// Check the not_after date
@@ -613,13 +650,16 @@ mod tests {
613
650
let config = CsrTemplate :: default ( ) ;
614
651
let id = "some-id" ;
615
652
616
- let params = KeyCertPair :: create_csr_parameters ( & config, id, & KeyKind :: New )
653
+ let ( params, signing_key ) = KeyCertPair :: create_csr_parameters ( & config, id, & KeyKind :: New )
617
654
. expect ( "Fail to get a certificate parameters" ) ;
618
655
656
+ let issuer = rcgen:: Issuer :: from_params ( & params, & signing_key) ;
619
657
let keypair = KeyCertPair {
620
- certificate : Zeroizing :: new (
621
- Certificate :: from_params ( params) . expect ( "Fail to create a certificate" ) ,
622
- ) ,
658
+ certificate : params
659
+ . signed_by ( & signing_key, & issuer)
660
+ . expect ( "Fail to create a certificate" ) ,
661
+ params,
662
+ signing_key,
623
663
} ;
624
664
625
665
// Check the subject
0 commit comments