1 use std::ops::{Deref, DerefMut}; 2 3 use serde::{Deserialize, Serialize}; 4 5 use rpki::repository::{crypto::KeyIdentifier, x509::Time}; 6 7 use crate::{ 8 commons::{ 9 api::{ 10 ActiveInfo, CertifiedKeyInfo, EntitlementClass, Handle, IssuanceRequest, PendingInfo, PendingKeyInfo, 11 RcvdCert, RepoInfo, RequestResourceLimit, ResourceClassKeysInfo, ResourceClassName, ResourceSet, 12 RevocationRequest, RollNewInfo, RollOldInfo, RollPendingInfo, 13 }, 14 crypto::KrillSigner, 15 error::Error, 16 KrillResult, 17 }, 18 daemon::ca::CaEvtDet, 19 }; 20 21 //------------ CertifiedKey -------------------------------------------------- 22 23 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 24 /// Describes a Key that is certified. I.e. it received an incoming certificate 25 /// and has at least a MFT and CRL. 26 pub struct CertifiedKey { 27 key_id: KeyIdentifier, 28 incoming_cert: RcvdCert, 29 request: Option<IssuanceRequest>, 30 #[serde(skip_serializing_if = "Option::is_none")] 31 old_repo: Option<RepoInfo>, 32 } 33 34 impl CertifiedKey { new(key_id: KeyIdentifier, incoming_cert: RcvdCert, request: Option<IssuanceRequest>) -> Self35 pub fn new(key_id: KeyIdentifier, incoming_cert: RcvdCert, request: Option<IssuanceRequest>) -> Self { 36 CertifiedKey { 37 key_id, 38 incoming_cert, 39 request, 40 old_repo: None, 41 } 42 } 43 create(incoming_cert: RcvdCert) -> Self44 pub fn create(incoming_cert: RcvdCert) -> Self { 45 let key_id = incoming_cert.subject_key_identifier(); 46 CertifiedKey { 47 key_id, 48 incoming_cert, 49 request: None, 50 old_repo: None, 51 } 52 } 53 as_info(&self) -> CertifiedKeyInfo54 pub fn as_info(&self) -> CertifiedKeyInfo { 55 CertifiedKeyInfo::new(self.key_id, self.incoming_cert.clone()) 56 } 57 key_id(&self) -> &KeyIdentifier58 pub fn key_id(&self) -> &KeyIdentifier { 59 &self.key_id 60 } incoming_cert(&self) -> &RcvdCert61 pub fn incoming_cert(&self) -> &RcvdCert { 62 &self.incoming_cert 63 } set_incoming_cert(&mut self, incoming_cert: RcvdCert)64 pub fn set_incoming_cert(&mut self, incoming_cert: RcvdCert) { 65 self.request = None; 66 self.incoming_cert = incoming_cert; 67 } 68 request(&self) -> Option<&IssuanceRequest>69 pub fn request(&self) -> Option<&IssuanceRequest> { 70 self.request.as_ref() 71 } add_request(&mut self, req: IssuanceRequest)72 pub fn add_request(&mut self, req: IssuanceRequest) { 73 self.request = Some(req) 74 } 75 set_old_repo(&mut self, repo: &RepoInfo)76 pub fn set_old_repo(&mut self, repo: &RepoInfo) { 77 self.old_repo = Some(repo.clone()) 78 } 79 wants_update( &self, handle: &Handle, rcn: &ResourceClassName, new_resources: &ResourceSet, new_not_after: Time, ) -> bool80 pub fn wants_update( 81 &self, 82 handle: &Handle, 83 rcn: &ResourceClassName, 84 new_resources: &ResourceSet, 85 new_not_after: Time, 86 ) -> bool { 87 // If resources have changed, then we need to request a new certificate. 88 let resources_diff = new_resources.difference(self.incoming_cert.resources()); 89 90 if !resources_diff.is_empty() { 91 info!( 92 "Will request new certificate for CA '{}' under RC '{}'. Resources have changed: '{}'", 93 handle, rcn, resources_diff 94 ); 95 return true; 96 } 97 98 // If the validity time eligibility has changed, then we *may* want to ask for a new 99 // certificate, but only if: 100 // a) our current certificate expires *after* the eligible time, because we probably should 101 // know.. 102 // b) the new not after time is significantly better than our current time, because we 103 // do not want to ask for new certificates every hour if the parent uses a simple 104 // strategy like: not-after = now + 1 year.. 105 // 106 // See issue #95 107 108 let not_after = self.incoming_cert().cert().validity().not_after(); 109 110 let now = Time::now().timestamp_millis(); 111 let until_not_after_millis = not_after.timestamp_millis() - now; 112 let until_new_not_after_millis = new_not_after.timestamp_millis() - now; 113 114 if until_new_not_after_millis < 0 { 115 // New not after time is in the past! 116 // 117 // This is rather odd. The parent should just exclude the resource class in the 118 // eligible entitlements instead. So, we will essentially just ignore this until 119 // they do. 120 warn!( 121 "Will NOT request certificate for CA '{}' under RC '{}', the eligible not after time is set in the past: {}", 122 handle, 123 rcn, 124 new_not_after.to_rfc3339() 125 ); 126 false 127 } else if until_not_after_millis == until_new_not_after_millis { 128 debug!( 129 "Will not request new certificate for CA '{}' under RC '{}'. Resources and not after time are unchanged.", 130 handle, 131 rcn, 132 ); 133 false 134 } else if until_new_not_after_millis < until_not_after_millis { 135 warn!( 136 "Parent of CA '{}' reduced not after time for certificate under RC '{}'", 137 handle, rcn, 138 ); 139 true 140 } else if until_not_after_millis <= 0 141 || (until_new_not_after_millis as f64 / until_not_after_millis as f64) > 1.1_f64 142 { 143 info!( 144 "Will request new certificate for CA '{}' under RC '{}'. Not after time increased to: {}", 145 handle, 146 rcn, 147 new_not_after.to_rfc3339() 148 ); 149 true 150 } else { 151 debug!( 152 "Will not request new certificate for CA '{}' under RC '{}'. Not after time increased by less than 10%: {}", 153 handle, 154 rcn, 155 new_not_after.to_rfc3339() 156 ); 157 false 158 } 159 } 160 } 161 162 pub type NewKey = CertifiedKey; 163 pub type CurrentKey = CertifiedKey; 164 165 //------------ PendingKey ---------------------------------------------------- 166 167 /// A Pending Key in a resource class. Should usually have an open 168 /// IssuanceRequest, and will be move to a 'new' or 'current' CertifiedKey 169 /// when a certificate is received. 170 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 171 pub struct PendingKey { 172 key_id: KeyIdentifier, 173 request: Option<IssuanceRequest>, 174 } 175 176 impl PendingKey { new(key_id: KeyIdentifier) -> Self177 pub fn new(key_id: KeyIdentifier) -> Self { 178 PendingKey { key_id, request: None } 179 } 180 as_info(&self) -> PendingKeyInfo181 pub fn as_info(&self) -> PendingKeyInfo { 182 PendingKeyInfo::new(self.key_id) 183 } 184 unwrap(self) -> (KeyIdentifier, Option<IssuanceRequest>)185 pub fn unwrap(self) -> (KeyIdentifier, Option<IssuanceRequest>) { 186 (self.key_id, self.request) 187 } 188 key_id(&self) -> &KeyIdentifier189 pub fn key_id(&self) -> &KeyIdentifier { 190 &self.key_id 191 } request(&self) -> Option<&IssuanceRequest>192 pub fn request(&self) -> Option<&IssuanceRequest> { 193 self.request.as_ref() 194 } add_request(&mut self, req: IssuanceRequest)195 pub fn add_request(&mut self, req: IssuanceRequest) { 196 self.request = Some(req) 197 } clear_request(&mut self)198 pub fn clear_request(&mut self) { 199 self.request = None 200 } 201 } 202 203 //------------ OldKey -------------------------------------------------------- 204 205 #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)] 206 pub struct OldKey { 207 key: CertifiedKey, 208 revoke_req: RevocationRequest, 209 } 210 211 impl OldKey { new(key: CertifiedKey, revoke_req: RevocationRequest) -> Self212 pub fn new(key: CertifiedKey, revoke_req: RevocationRequest) -> Self { 213 OldKey { key, revoke_req } 214 } 215 key(&self) -> &CertifiedKey216 pub fn key(&self) -> &CertifiedKey { 217 &self.key 218 } revoke_req(&self) -> &RevocationRequest219 pub fn revoke_req(&self) -> &RevocationRequest { 220 &self.revoke_req 221 } 222 } 223 224 impl Deref for OldKey { 225 type Target = CertifiedKey; 226 deref(&self) -> &Self::Target227 fn deref(&self) -> &Self::Target { 228 &self.key 229 } 230 } 231 232 impl DerefMut for OldKey { deref_mut(&mut self) -> &mut Self::Target233 fn deref_mut(&mut self) -> &mut Self::Target { 234 &mut self.key 235 } 236 } 237 238 //------------ KeyState ------------------------------------------------------ 239 240 /// This type contains the keys for a resource class and guards that keys 241 /// are created, activated, rolled and retired properly. 242 #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq)] 243 #[allow(clippy::large_enum_variant)] 244 #[serde(rename_all = "snake_case")] 245 pub enum KeyState { 246 Pending(PendingKey), 247 Active(CurrentKey), 248 RollPending(PendingKey, CurrentKey), 249 RollNew(NewKey, CurrentKey), 250 RollOld(CurrentKey, OldKey), 251 } 252 253 impl KeyState { create(pending_key: KeyIdentifier) -> Self254 pub fn create(pending_key: KeyIdentifier) -> Self { 255 KeyState::Pending(PendingKey::new(pending_key)) 256 } 257 add_request(&mut self, key_id: KeyIdentifier, req: IssuanceRequest)258 pub fn add_request(&mut self, key_id: KeyIdentifier, req: IssuanceRequest) { 259 match self { 260 KeyState::Pending(pending) => pending.add_request(req), 261 KeyState::Active(current) => current.add_request(req), 262 KeyState::RollPending(pending, current) => { 263 if pending.key_id() == &key_id { 264 pending.add_request(req) 265 } else { 266 current.add_request(req) 267 } 268 } 269 KeyState::RollNew(new, current) => { 270 if new.key_id() == &key_id { 271 new.add_request(req) 272 } else { 273 current.add_request(req) 274 } 275 } 276 KeyState::RollOld(current, old) => { 277 if current.key_id() == &key_id { 278 current.add_request(req) 279 } else { 280 old.add_request(req) 281 } 282 } 283 } 284 } 285 286 /// Revoke all current keys revoke(&self, class_name: ResourceClassName, signer: &KrillSigner) -> KrillResult<Vec<RevocationRequest>>287 pub fn revoke(&self, class_name: ResourceClassName, signer: &KrillSigner) -> KrillResult<Vec<RevocationRequest>> { 288 match self { 289 KeyState::Pending(_pending) => Ok(vec![]), // nothing to revoke 290 KeyState::Active(current) | KeyState::RollPending(_, current) => { 291 let revoke_current = Self::revoke_key(class_name, current.key_id(), signer)?; 292 Ok(vec![revoke_current]) 293 } 294 KeyState::RollNew(new, current) => { 295 let revoke_new = Self::revoke_key(class_name.clone(), new.key_id(), signer)?; 296 let revoke_current = Self::revoke_key(class_name, current.key_id(), signer)?; 297 Ok(vec![revoke_new, revoke_current]) 298 } 299 KeyState::RollOld(current, old) => { 300 let revoke_current = Self::revoke_key(class_name, current.key_id(), signer)?; 301 let revoke_old = old.revoke_req().clone(); 302 Ok(vec![revoke_current, revoke_old]) 303 } 304 } 305 } 306 revoke_key( class_name: ResourceClassName, key_id: &KeyIdentifier, signer: &KrillSigner, ) -> KrillResult<RevocationRequest>307 fn revoke_key( 308 class_name: ResourceClassName, 309 key_id: &KeyIdentifier, 310 signer: &KrillSigner, 311 ) -> KrillResult<RevocationRequest> { 312 let ki = signer.get_key_info(key_id).map_err(Error::signer)?.key_identifier(); 313 314 Ok(RevocationRequest::new(class_name, ki)) 315 } 316 make_entitlement_events( &self, handle: &Handle, rcn: ResourceClassName, entitlement: &EntitlementClass, base_repo: &RepoInfo, name_space: &str, signer: &KrillSigner, ) -> KrillResult<Vec<CaEvtDet>>317 pub fn make_entitlement_events( 318 &self, 319 handle: &Handle, 320 rcn: ResourceClassName, 321 entitlement: &EntitlementClass, 322 base_repo: &RepoInfo, 323 name_space: &str, 324 signer: &KrillSigner, 325 ) -> KrillResult<Vec<CaEvtDet>> { 326 let mut keys_for_requests = vec![]; 327 328 match self { 329 KeyState::Pending(pending) => { 330 keys_for_requests.push((base_repo, pending.key_id())); 331 } 332 KeyState::Active(current) => { 333 if current.wants_update(handle, &rcn, entitlement.resource_set(), entitlement.not_after()) { 334 let repo = current.old_repo.as_ref().unwrap_or(base_repo); 335 keys_for_requests.push((repo, current.key_id())); 336 } 337 } 338 KeyState::RollPending(pending, current) => { 339 keys_for_requests.push((base_repo, pending.key_id())); 340 if current.wants_update(handle, &rcn, entitlement.resource_set(), entitlement.not_after()) { 341 let repo = current.old_repo.as_ref().unwrap_or(base_repo); 342 keys_for_requests.push((repo, current.key_id())); 343 } 344 } 345 KeyState::RollNew(new, current) => { 346 if new.wants_update(handle, &rcn, entitlement.resource_set(), entitlement.not_after()) { 347 let repo = new.old_repo.as_ref().unwrap_or(base_repo); 348 keys_for_requests.push((repo, new.key_id())); 349 } 350 if current.wants_update(handle, &rcn, entitlement.resource_set(), entitlement.not_after()) { 351 let repo = current.old_repo.as_ref().unwrap_or(base_repo); 352 keys_for_requests.push((repo, current.key_id())); 353 } 354 } 355 KeyState::RollOld(current, old) => { 356 if current.wants_update(handle, &rcn, entitlement.resource_set(), entitlement.not_after()) { 357 let repo = current.old_repo.as_ref().unwrap_or(base_repo); 358 keys_for_requests.push((repo, current.key_id())); 359 } 360 if old.wants_update(handle, &rcn, entitlement.resource_set(), entitlement.not_after()) { 361 let repo = old.old_repo.as_ref().unwrap_or(base_repo); 362 keys_for_requests.push((repo, current.key_id())); 363 } 364 } 365 } 366 367 let mut res = vec![]; 368 369 for (base_repo, key_id) in keys_for_requests.into_iter() { 370 let req = 371 self.create_issuance_req(base_repo, name_space, entitlement.class_name().clone(), key_id, signer)?; 372 373 res.push(CaEvtDet::CertificateRequested { 374 resource_class_name: rcn.clone(), 375 req, 376 ki: *key_id, 377 }); 378 } 379 380 for key in entitlement.issued().iter().map(|c| c.subject_key_identifier()) { 381 if !self.knows_key(key) { 382 let revoke_req = RevocationRequest::new(entitlement.class_name().clone(), key); 383 res.push(CaEvtDet::UnexpectedKeyFound { 384 resource_class_name: rcn.clone(), 385 revoke_req, 386 }); 387 } 388 } 389 390 Ok(res) 391 } 392 request_certs_new_repo( &self, rcn: ResourceClassName, base_repo: &RepoInfo, name_space: &str, signer: &KrillSigner, ) -> KrillResult<Vec<CaEvtDet>>393 pub fn request_certs_new_repo( 394 &self, 395 rcn: ResourceClassName, 396 base_repo: &RepoInfo, 397 name_space: &str, 398 signer: &KrillSigner, 399 ) -> KrillResult<Vec<CaEvtDet>> { 400 let mut res = vec![]; 401 402 let keys = match self { 403 KeyState::Pending(pending) => vec![pending.key_id()], 404 KeyState::Active(current) => vec![current.key_id()], 405 KeyState::RollPending(pending, current) => vec![pending.key_id(), current.key_id()], 406 KeyState::RollNew(new, current) => vec![new.key_id(), current.key_id()], 407 KeyState::RollOld(current, old) => vec![current.key_id(), old.key_id()], 408 }; 409 410 for ki in keys { 411 let req = self.create_issuance_req(base_repo, name_space, rcn.clone(), ki, signer)?; 412 res.push(CaEvtDet::CertificateRequested { 413 resource_class_name: rcn.clone(), 414 req, 415 ki: *ki, 416 }); 417 } 418 419 Ok(res) 420 } 421 422 /// Returns all open certificate requests cert_requests(&self) -> Vec<IssuanceRequest>423 pub fn cert_requests(&self) -> Vec<IssuanceRequest> { 424 let mut res = vec![]; 425 match self { 426 KeyState::Pending(pending) => { 427 if let Some(r) = pending.request() { 428 res.push(r.clone()) 429 } 430 } 431 KeyState::Active(current) => { 432 if let Some(r) = current.request() { 433 res.push(r.clone()) 434 } 435 } 436 KeyState::RollPending(pending, current) => { 437 if let Some(r) = pending.request() { 438 res.push(r.clone()) 439 } 440 if let Some(r) = current.request() { 441 res.push(r.clone()) 442 } 443 } 444 KeyState::RollNew(new, current) => { 445 if let Some(r) = new.request() { 446 res.push(r.clone()) 447 } 448 if let Some(r) = current.request() { 449 res.push(r.clone()) 450 } 451 } 452 KeyState::RollOld(current, old) => { 453 if let Some(r) = current.request() { 454 res.push(r.clone()) 455 } 456 if let Some(r) = old.request() { 457 res.push(r.clone()) 458 } 459 } 460 } 461 res 462 } 463 464 /// Creates a Csr for the given key. create_issuance_req( &self, base_repo: &RepoInfo, name_space: &str, class_name: ResourceClassName, key: &KeyIdentifier, signer: &KrillSigner, ) -> KrillResult<IssuanceRequest>465 fn create_issuance_req( 466 &self, 467 base_repo: &RepoInfo, 468 name_space: &str, 469 class_name: ResourceClassName, 470 key: &KeyIdentifier, 471 signer: &KrillSigner, 472 ) -> KrillResult<IssuanceRequest> { 473 let csr = signer.sign_csr(base_repo, name_space, key)?; 474 Ok(IssuanceRequest::new(class_name, RequestResourceLimit::default(), csr)) 475 } 476 477 /// Returns the revoke request if there is an old key. revoke_request(&self) -> Option<&RevocationRequest>478 pub fn revoke_request(&self) -> Option<&RevocationRequest> { 479 match self { 480 KeyState::RollOld(_current, old) => Some(old.revoke_req()), 481 _ => None, 482 } 483 } 484 as_info(&self) -> ResourceClassKeysInfo485 pub fn as_info(&self) -> ResourceClassKeysInfo { 486 match self.clone() { 487 KeyState::Pending(p) => ResourceClassKeysInfo::Pending(PendingInfo { 488 _pending_key: p.as_info(), 489 }), 490 KeyState::Active(c) => ResourceClassKeysInfo::Active(ActiveInfo { 491 _active_key: c.as_info(), 492 }), 493 KeyState::RollPending(p, c) => ResourceClassKeysInfo::RollPending(RollPendingInfo { 494 _pending_key: p.as_info(), 495 _active_key: c.as_info(), 496 }), 497 KeyState::RollNew(n, c) => ResourceClassKeysInfo::RollNew(RollNewInfo { 498 _new_key: n.as_info(), 499 _active_key: c.as_info(), 500 }), 501 KeyState::RollOld(c, o) => ResourceClassKeysInfo::RollOld(RollOldInfo { 502 _old_key: o.as_info(), 503 _active_key: c.as_info(), 504 }), 505 } 506 } 507 } 508 509 /// # Key Life Cycle 510 /// 511 impl KeyState { 512 /// Initiates a key roll if the current state is 'Active'. This will return event details 513 /// for a newly create pending key and requested certificate for it. keyroll_initiate( &self, resource_class_name: ResourceClassName, parent_class_name: ResourceClassName, base_repo: &RepoInfo, name_space: &str, signer: &KrillSigner, ) -> KrillResult<Vec<CaEvtDet>>514 pub fn keyroll_initiate( 515 &self, 516 resource_class_name: ResourceClassName, 517 parent_class_name: ResourceClassName, 518 base_repo: &RepoInfo, 519 name_space: &str, 520 signer: &KrillSigner, 521 ) -> KrillResult<Vec<CaEvtDet>> { 522 match self { 523 KeyState::Active(_current) => { 524 let pending_key_id = signer.create_key()?; 525 526 let req = 527 self.create_issuance_req(base_repo, name_space, parent_class_name, &pending_key_id, signer)?; 528 529 Ok(vec![ 530 CaEvtDet::KeyRollPendingKeyAdded { 531 resource_class_name: resource_class_name.clone(), 532 pending_key_id, 533 }, 534 CaEvtDet::CertificateRequested { 535 resource_class_name, 536 req, 537 ki: pending_key_id, 538 }, 539 ]) 540 } 541 _ => Ok(vec![]), 542 } 543 } 544 545 /// Marks the new key as current, and the current key as old, and requests revocation of 546 /// the old key. keyroll_activate( &self, resource_class_name: ResourceClassName, parent_class_name: ResourceClassName, signer: &KrillSigner, ) -> KrillResult<CaEvtDet>547 pub fn keyroll_activate( 548 &self, 549 resource_class_name: ResourceClassName, 550 parent_class_name: ResourceClassName, 551 signer: &KrillSigner, 552 ) -> KrillResult<CaEvtDet> { 553 match self { 554 KeyState::RollNew(_new, current) => { 555 let revoke_req = Self::revoke_key(parent_class_name, current.key_id(), signer)?; 556 Ok(CaEvtDet::KeyRollActivated { 557 resource_class_name, 558 revoke_req, 559 }) 560 } 561 _ => Err(Error::KeyUseNoNewKey), 562 } 563 } 564 565 /// Returns the new key, iff there is a key roll in progress and there is a new key. new_key(&self) -> Option<&CertifiedKey>566 pub fn new_key(&self) -> Option<&CertifiedKey> { 567 match self { 568 KeyState::RollNew(new, _) => Some(new), 569 _ => None, 570 } 571 } 572 knows_key(&self, key_id: KeyIdentifier) -> bool573 fn knows_key(&self, key_id: KeyIdentifier) -> bool { 574 match self { 575 KeyState::Pending(pending) => pending.key_id == key_id, 576 KeyState::Active(current) => current.key_id == key_id, 577 KeyState::RollPending(pending, current) => pending.key_id == key_id || current.key_id == key_id, 578 KeyState::RollNew(new, current) => new.key_id == key_id || current.key_id == key_id, 579 KeyState::RollOld(current, old) => current.key_id == key_id || old.key_id == key_id, 580 } 581 } 582 } 583 584 /// # Migrate repositories 585 /// 586 impl KeyState { 587 /// Mark an old_repo for the current key, so that a new repo can be introduced in a pending 588 /// key and a keyroll can be done. set_old_repo_if_in_active_state(&mut self, repo: &RepoInfo)589 pub fn set_old_repo_if_in_active_state(&mut self, repo: &RepoInfo) { 590 if let KeyState::Active(current) = self { 591 current.set_old_repo(repo); 592 } 593 } 594 } 595