• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oasisprotocol / oasis-core / #4463

13 Feb 2024 09:12AM UTC coverage: 45.523% (+0.04%) from 45.481%
#4463

Pull #5554

peternose
go/p2p/peermgmt: Debugging storage-early-state-sync test
Pull Request #5554: keymanager/runtime: Use insecure RPC requests for ephemeral public keys

0 of 4 new or added lines in 3 files covered. (0.0%)

5 existing lines in 3 files now uncovered.

2969 of 6522 relevant lines covered (45.52%)

1.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/keymanager/src/runtime/methods.rs
1
//! Methods exported to remote clients via EnclaveRPC.
2
use std::{
3
    collections::{HashMap, HashSet},
4
    convert::TryInto,
5
    sync::Arc,
6
};
7

8
use anyhow::Result;
9

10
use oasis_core_runtime::{
11
    common::{
12
        crypto::{
13
            mrae::{
14
                deoxysii::{self, Opener},
15
                nonce::Nonce,
16
            },
17
            signature::{self, Signer},
18
            x25519,
19
        },
20
        namespace::Namespace,
21
        sgx::EnclaveIdentity,
22
    },
23
    consensus::{
24
        beacon::EpochTime,
25
        keymanager::{
26
            EncryptedEphemeralSecret, EncryptedMasterSecret, EncryptedSecret,
27
            SignedEncryptedEphemeralSecret, SignedEncryptedMasterSecret,
28
        },
29
        state::{
30
            beacon::ImmutableState as BeaconState,
31
            keymanager::{ImmutableState as KeyManagerState, Status},
32
            registry::ImmutableState as RegistryState,
33
        },
34
    },
35
    enclave_rpc::Context as RpcContext,
36
    future::block_on,
37
    policy::PolicyVerifier,
38
    runtime_context, BUILD_INFO,
39
};
40

41
use crate::{
42
    api::{
43
        EphemeralKeyRequest, GenerateEphemeralSecretRequest, GenerateEphemeralSecretResponse,
44
        GenerateMasterSecretRequest, GenerateMasterSecretResponse, InitRequest, InitResponse,
45
        KeyManagerError, LoadEphemeralSecretRequest, LoadMasterSecretRequest, LongTermKeyRequest,
46
        ReplicateEphemeralSecretRequest, ReplicateEphemeralSecretResponse,
47
        ReplicateMasterSecretRequest, ReplicateMasterSecretResponse, SignedInitResponse,
48
    },
49
    client::RemoteClient,
50
    crypto::{
51
        kdf::{Kdf, State},
52
        pack_runtime_id_epoch, pack_runtime_id_generation_epoch, unpack_encrypted_secret_nonce,
53
        KeyPair, Secret, SignedPublicKey, SECRET_SIZE,
54
    },
55
    policy::Policy,
56
    runtime::context::Context as KmContext,
57
    secrets::{KeyManagerSecretProvider, SecretProvider},
58
};
59

60
/// Maximum age of an ephemeral key in the number of epochs.
61
const MAX_EPHEMERAL_KEY_AGE: EpochTime = 10;
62
/// Maximum age of a fresh height in the number of blocks.
63
///
64
/// A height is considered fresh if it is not more than specified amount
65
/// of blocks lower than the height of the latest trust root.
66
const MAX_FRESH_HEIGHT_AGE: u64 = 50;
67

68
/// Initialize the Kdf.
69
pub fn init_kdf(ctx: &RpcContext, req: &InitRequest) -> Result<SignedInitResponse> {
×
70
    let rctx = runtime_context!(ctx, KmContext);
×
71
    let runtime_id = rctx.runtime_id;
×
72
    let storage = ctx.untrusted_local_storage;
×
73

UNCOV
74
    let status = req.status.clone();
×
UNCOV
75
    let status = validate_key_manager_status(ctx, runtime_id, status)?;
×
76

77
    // Empty policies are allowed only in unsafe builds.
78
    let policy = Policy::global();
×
79
    let policy_checksum = policy.init(storage, status.policy)?;
×
80

81
    // Initialize or update the KDF.
82
    let generation = status.generation;
×
83
    let checksum = status.checksum;
×
84
    let nodes = status.nodes;
×
85
    let epoch = consensus_epoch(ctx)?;
×
86
    let client = key_manager_client_for_replication(ctx);
×
87
    let provider = KeyManagerSecretProvider::new(client, nodes);
×
88

89
    let kdf = Kdf::global();
×
90
    let state = kdf.init(storage, runtime_id, generation, checksum, epoch, &provider)?;
×
91

92
    // State is up-to-date, build the response and sign it with the RAK.
93
    sign_init_response(ctx, state, policy_checksum)
×
94
}
95

96
/// See `Kdf::get_or_create_keys`.
97
pub fn get_or_create_keys(ctx: &RpcContext, req: &LongTermKeyRequest) -> Result<KeyPair> {
×
98
    authorize_private_key_generation(ctx, &req.runtime_id)?;
×
99
    validate_height_freshness(ctx, req.height)?;
×
100

101
    Kdf::global().get_or_create_longterm_keys(
×
102
        ctx.untrusted_local_storage,
×
103
        req.runtime_id,
×
104
        req.key_pair_id,
×
105
        req.generation,
×
106
    )
107
}
108

109
/// See `Kdf::get_public_key`.
110
pub fn get_public_key(ctx: &RpcContext, req: &LongTermKeyRequest) -> Result<SignedPublicKey> {
×
111
    // No authentication or authorization.
112
    // Absolutely anyone is allowed to query public long-term keys.
113

114
    let kdf = Kdf::global();
×
115
    let pk = kdf.get_public_longterm_key(
×
116
        ctx.untrusted_local_storage,
×
117
        req.runtime_id,
×
118
        req.key_pair_id,
×
119
        req.generation,
×
120
    )?;
121
    let sig = kdf.sign_public_key(pk, req.runtime_id, req.key_pair_id, None)?;
×
122
    Ok(sig)
×
123
}
124

125
/// See `Kdf::get_or_create_ephemeral_keys`.
126
pub fn get_or_create_ephemeral_keys(
×
127
    ctx: &RpcContext,
128
    req: &EphemeralKeyRequest,
129
) -> Result<KeyPair> {
130
    authorize_private_key_generation(ctx, &req.runtime_id)?;
×
131
    validate_ephemeral_key_epoch(ctx, req.epoch)?;
×
132
    validate_height_freshness(ctx, req.height)?;
×
133

134
    Kdf::global().get_or_create_ephemeral_keys(req.runtime_id, req.key_pair_id, req.epoch)
×
135
}
136

137
/// See `Kdf::get_public_ephemeral_key`.
138
pub fn get_public_ephemeral_key(
×
139
    ctx: &RpcContext,
140
    req: &EphemeralKeyRequest,
141
) -> Result<SignedPublicKey> {
142
    // No authentication or authorization.
143
    // Absolutely anyone is allowed to query public ephemeral keys.
144
    validate_ephemeral_key_epoch(ctx, req.epoch)?;
×
145

146
    let kdf = Kdf::global();
×
147
    let pk = kdf.get_public_ephemeral_key(req.runtime_id, req.key_pair_id, req.epoch)?;
×
NEW
148
    let sig = kdf.sign_public_key(pk, req.runtime_id, req.key_pair_id, Some(req.epoch))?;
×
149

150
    Ok(sig)
×
151
}
152

153
/// See `Kdf::replicate_master_secret`.
154
pub fn replicate_master_secret(
×
155
    ctx: &RpcContext,
156
    req: &ReplicateMasterSecretRequest,
157
) -> Result<ReplicateMasterSecretResponse> {
158
    authorize_secret_replication(ctx)?;
×
159
    validate_height_freshness(ctx, req.height)?;
×
160

161
    let master_secret =
×
162
        Kdf::global().replicate_master_secret(ctx.untrusted_local_storage, req.generation)?;
163
    let checksum = Kdf::load_checksum(ctx.untrusted_local_storage, req.generation);
×
164

165
    Ok(ReplicateMasterSecretResponse {
×
166
        master_secret,
×
167
        checksum,
168
    })
169
}
170

171
/// See `Kdf::replicate_ephemeral_secret`.
172
pub fn replicate_ephemeral_secret(
×
173
    ctx: &RpcContext,
174
    req: &ReplicateEphemeralSecretRequest,
175
) -> Result<ReplicateEphemeralSecretResponse> {
176
    authorize_secret_replication(ctx)?;
×
177
    validate_height_freshness(ctx, req.height)?;
×
178

179
    let ephemeral_secret = Kdf::global().replicate_ephemeral_secret(req.epoch)?;
×
180
    Ok(ReplicateEphemeralSecretResponse { ephemeral_secret })
×
181
}
182

183
/// Generate a master secret and encrypt it using the key manager's REK keys.
184
pub fn generate_master_secret(
×
185
    ctx: &RpcContext,
186
    req: &GenerateMasterSecretRequest,
187
) -> Result<GenerateMasterSecretResponse> {
188
    let kdf = Kdf::global();
×
189
    let runtime_id = kdf.runtime_id()?;
×
190

191
    // Allow generating a secret for the next epoch only.
192
    let epoch = consensus_epoch(ctx)? + 1;
×
193
    if epoch != req.epoch {
×
194
        return Err(KeyManagerError::InvalidEpoch(epoch, req.epoch).into());
×
195
    }
196

197
    // Generate a secret and encrypt it.
198
    // Note that the checksum can be computed for the next generation only.
199
    let generation = req.generation;
×
200
    let secret = Secret::generate();
×
201
    let checksum = kdf.checksum_master_secret_proposal(runtime_id, &secret, generation)?;
×
202
    let additional_data = pack_runtime_id_generation_epoch(&runtime_id, generation, epoch);
×
203
    let secret = encrypt_secret(ctx, secret, checksum, additional_data, runtime_id)?;
×
204

205
    // Sign the secret.
206
    let signer: Arc<dyn Signer> = ctx.identity.clone();
×
207
    let secret = EncryptedMasterSecret {
208
        runtime_id,
209
        generation,
210
        epoch,
211
        secret,
212
    };
213
    let signed_secret = SignedEncryptedMasterSecret::new(secret, &signer)?;
×
214

215
    Ok(GenerateMasterSecretResponse { signed_secret })
×
216
}
217

218
/// Generate an ephemeral secret and encrypt it using the key manager's REK keys.
219
pub fn generate_ephemeral_secret(
×
220
    ctx: &RpcContext,
221
    req: &GenerateEphemeralSecretRequest,
222
) -> Result<GenerateEphemeralSecretResponse> {
223
    let kdf = Kdf::global();
×
224
    let runtime_id = kdf.runtime_id()?;
×
225

226
    // Allow generating a secret for the next epoch only.
227
    let epoch = consensus_epoch(ctx)? + 1;
×
228
    if epoch != req.epoch {
×
229
        return Err(KeyManagerError::InvalidEpoch(epoch, req.epoch).into());
×
230
    }
231

232
    // Generate a secret and encrypt it.
233
    let secret = Secret::generate();
×
234
    let checksum = Kdf::checksum_ephemeral_secret(&runtime_id, &secret, epoch);
×
235
    let additional_data = pack_runtime_id_epoch(&runtime_id, epoch);
×
236
    let secret = encrypt_secret(ctx, secret, checksum, additional_data, runtime_id)?;
×
237

238
    // Sign the secret.
239
    let signer: Arc<dyn Signer> = ctx.identity.clone();
×
240
    let secret = EncryptedEphemeralSecret {
241
        runtime_id,
242
        epoch,
243
        secret,
244
    };
245
    let signed_secret = SignedEncryptedEphemeralSecret::new(secret, &signer)?;
×
246

247
    Ok(GenerateEphemeralSecretResponse { signed_secret })
×
248
}
249

250
/// Encrypt a secret using the Deoxys-II MRAE algorithm and the key manager's REK keys.
251
fn encrypt_secret(
×
252
    ctx: &RpcContext,
253
    secret: Secret,
254
    checksum: Vec<u8>,
255
    additional_data: Vec<u8>,
256
    runtime_id: Namespace,
257
) -> Result<EncryptedSecret> {
258
    // Fetch REK keys of the key manager committee members.
259
    let rek_keys = key_manager_rek_keys(ctx, runtime_id)?;
×
260
    let rek_keys: HashSet<_> = rek_keys.values().collect();
×
261
    // Abort if our REK hasn't been published.
262
    if rek_keys.get(&ctx.identity.public_rek()).is_none() {
×
263
        return Err(KeyManagerError::REKNotPublished.into());
×
264
    }
265
    // Encrypt the secret.
266
    let priv_key = x25519::PrivateKey::generate();
×
267
    let pub_key = x25519::PublicKey::from(&priv_key);
×
268
    let mut nonce = Nonce::generate();
×
269
    let plaintext = secret.0.to_vec();
×
270
    let mut ciphertexts = HashMap::new();
×
271
    for &rek in rek_keys.iter() {
×
272
        nonce.increment()?;
×
273

274
        let mut ciphertext = deoxysii::box_seal(
275
            &nonce,
×
276
            plaintext.clone(),
×
277
            additional_data.clone(),
×
278
            &rek.0,
279
            &priv_key.0,
280
        )?;
281
        ciphertext.extend_from_slice(&nonce.to_vec());
×
282

283
        ciphertexts.insert(*rek, ciphertext);
×
284
    }
285

286
    Ok(EncryptedSecret {
×
287
        checksum,
×
288
        pub_key,
289
        ciphertexts,
×
290
    })
291
}
292

293
/// Decrypt and store a proposal for the next master secret.
294
pub fn load_master_secret(ctx: &RpcContext, req: &LoadMasterSecretRequest) -> Result<()> {
×
295
    let signed_secret = validate_signed_master_secret(ctx, &req.signed_secret)?;
×
296

297
    let secret = match decrypt_master_secret(ctx, &signed_secret)? {
×
298
        Some(secret) => secret,
×
299
        None => return Ok(()),
×
300
    };
301

302
    Kdf::global().add_master_secret_proposal(
×
303
        ctx.untrusted_local_storage,
×
304
        &signed_secret.runtime_id,
×
305
        secret,
×
306
        signed_secret.generation,
×
307
        &signed_secret.secret.checksum,
308
    )
309
}
310

311
/// Decrypt and store an ephemeral secret. If decryption fails, try to replicate the secret
312
/// from another key manager enclave.
313
pub fn load_ephemeral_secret(ctx: &RpcContext, req: &LoadEphemeralSecretRequest) -> Result<()> {
×
314
    let signed_secret = validate_signed_ephemeral_secret(ctx, &req.signed_secret)?;
×
315

316
    let secret = match decrypt_ephemeral_secret(ctx, &signed_secret)? {
×
317
        Some(secret) => secret,
×
318
        None => {
319
            let nodes = nodes_with_ephemeral_secret(ctx, &signed_secret)?;
×
320
            let client = key_manager_client_for_replication(ctx);
×
321

322
            KeyManagerSecretProvider::new(client, nodes)
×
323
                .ephemeral_secret_iter(signed_secret.epoch)
×
324
                .find(|secret| {
×
325
                    let checksum = Kdf::checksum_ephemeral_secret(
×
326
                        &signed_secret.runtime_id,
×
327
                        secret,
328
                        signed_secret.epoch,
×
329
                    );
330
                    checksum == signed_secret.secret.checksum
×
331
                })
332
                .ok_or(KeyManagerError::EphemeralSecretNotReplicated(
×
333
                    signed_secret.epoch,
×
334
                ))?
335
        }
336
    };
337

338
    Kdf::global().add_ephemeral_secret(
×
339
        &signed_secret.runtime_id,
×
340
        secret,
×
341
        signed_secret.epoch,
×
342
        &signed_secret.secret.checksum,
343
    )
344
}
345

346
/// Decrypt master secret with local REK key.
347
fn decrypt_master_secret(
×
348
    ctx: &RpcContext,
349
    secret: &EncryptedMasterSecret,
350
) -> Result<Option<Secret>> {
351
    let generation = secret.generation;
×
352
    let epoch = secret.epoch;
×
353
    let runtime_id = secret.runtime_id;
×
354
    let rek = ctx.identity.public_rek();
×
355

356
    let ciphertext = match secret.secret.ciphertexts.get(&rek) {
×
357
        Some(ciphertext) => ciphertext,
×
358
        None => return Ok(None),
×
359
    };
360

361
    let (ciphertext, nonce) =
×
362
        unpack_encrypted_secret_nonce(ciphertext).ok_or(KeyManagerError::InvalidCiphertext)?;
363
    let additional_data = pack_runtime_id_generation_epoch(&runtime_id, generation, epoch);
×
364
    let plaintext = ctx.identity.box_open(
×
365
        &nonce,
366
        ciphertext,
×
367
        additional_data,
×
368
        &secret.secret.pub_key.0,
×
369
    )?;
370

371
    if plaintext.len() != SECRET_SIZE {
×
372
        return Err(KeyManagerError::InvalidCiphertext.into());
×
373
    }
374

375
    let secret = Secret(plaintext.try_into().expect("slice with incorrect length"));
×
376

377
    Ok(Some(secret))
×
378
}
379

380
/// Decrypt ephemeral secret with local REK key.
381
fn decrypt_ephemeral_secret(
×
382
    ctx: &RpcContext,
383
    secret: &EncryptedEphemeralSecret,
384
) -> Result<Option<Secret>> {
385
    let epoch = secret.epoch;
×
386
    let runtime_id = secret.runtime_id;
×
387
    let rek = ctx.identity.public_rek();
×
388

389
    let ciphertext = match secret.secret.ciphertexts.get(&rek) {
×
390
        Some(ciphertext) => ciphertext,
×
391
        None => return Ok(None),
×
392
    };
393

394
    let (ciphertext, nonce) =
×
395
        unpack_encrypted_secret_nonce(ciphertext).ok_or(KeyManagerError::InvalidCiphertext)?;
396
    let additional_data = pack_runtime_id_epoch(&runtime_id, epoch);
×
397
    let plaintext = ctx.identity.box_open(
×
398
        &nonce,
399
        ciphertext,
×
400
        additional_data,
×
401
        &secret.secret.pub_key.0,
×
402
    )?;
403

404
    if plaintext.len() != SECRET_SIZE {
×
405
        return Err(KeyManagerError::InvalidCiphertext.into());
×
406
    }
407

408
    let secret = Secret(plaintext.try_into().expect("slice with incorrect length"));
×
409

410
    Ok(Some(secret))
×
411
}
412

413
/// Key manager client for master and ephemeral secret replication.
414
fn key_manager_client_for_replication(ctx: &RpcContext) -> RemoteClient {
×
415
    let rctx = runtime_context!(ctx, KmContext);
×
416
    let protocol = rctx.protocol.clone();
×
417
    let runtime_id = rctx.runtime_id;
×
418

419
    RemoteClient::new_runtime_with_enclaves_and_policy(
420
        runtime_id,
421
        Some(runtime_id),
×
422
        Policy::global().may_replicate_from(),
×
423
        ctx.identity.quote_policy(),
×
424
        protocol,
×
425
        ctx.consensus_verifier.clone(),
×
426
        ctx.identity.clone(),
×
427
        1, // Not used, doesn't matter.
428
        vec![],
×
429
    )
430
}
431

432
/// Create init response and sign it with RAK.
433
fn sign_init_response(
×
434
    ctx: &RpcContext,
435
    state: State,
436
    policy_checksum: Vec<u8>,
437
) -> Result<SignedInitResponse> {
438
    let is_secure = BUILD_INFO.is_secure && !Policy::unsafe_skip();
×
439
    let init_response = InitResponse {
440
        is_secure,
441
        checksum: state.checksum,
×
442
        next_checksum: state.next_checksum,
×
443
        policy_checksum,
444
        rsk: state.signing_key,
×
445
        next_rsk: state.next_signing_key,
×
446
    };
447
    let signer: Arc<dyn Signer> = ctx.identity.clone();
×
448
    SignedInitResponse::new(init_response, &signer)
×
449
}
450

451
/// Authorize the remote enclave so that the private keys are never released to an incorrect enclave.
452
fn authorize_private_key_generation(ctx: &RpcContext, runtime_id: &Namespace) -> Result<()> {
×
453
    if Policy::unsafe_skip() {
×
454
        return Ok(()); // Authorize unsafe builds always.
×
455
    }
456
    let remote_enclave = authenticate(ctx)?;
×
457
    Policy::global().may_get_or_create_keys(remote_enclave, runtime_id)
×
458
}
459

460
/// Authorize the remote enclave so that the master and ephemeral secrets are never replicated
461
/// to an incorrect enclave.
462
fn authorize_secret_replication(ctx: &RpcContext) -> Result<()> {
×
463
    if Policy::unsafe_skip() {
×
464
        return Ok(()); // Authorize unsafe builds always.
×
465
    }
466
    let remote_enclave = authenticate(ctx)?;
×
467
    Policy::global().may_replicate_secret(remote_enclave)
×
468
}
469

470
/// Authenticate the remote enclave based on the MRSIGNER/MRENCLAVE/request.
471
fn authenticate<'a>(ctx: &'a RpcContext) -> Result<&'a EnclaveIdentity> {
×
472
    let si = ctx.session_info.as_ref();
×
473
    let si = si.ok_or(KeyManagerError::NotAuthenticated)?;
×
474
    Ok(&si.verified_quote.identity)
×
475
}
476

477
/// Fetch current epoch from the consensus layer.
478
fn consensus_epoch(ctx: &RpcContext) -> Result<EpochTime> {
×
479
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
480
    let beacon_state = BeaconState::new(&consensus_state);
×
481
    let consensus_epoch = beacon_state.epoch()?;
×
482

483
    Ok(consensus_epoch)
×
484
}
485

486
/// Verify that the key manager status has been published in the consensus layer.
487
fn validate_key_manager_status(
×
488
    ctx: &RpcContext,
489
    runtime_id: Namespace,
490
    status: Status,
491
) -> Result<Status> {
492
    let consensus_verifier = ctx.consensus_verifier.clone();
×
493
    let verifier = PolicyVerifier::new(consensus_verifier);
×
494

495
    verifier.verify_key_manager_status(status, runtime_id)
×
496
}
497

498
/// Validate that the epoch used for derivation of ephemeral private keys is not
499
/// in the future or too far back in the past.
500
fn validate_ephemeral_key_epoch(ctx: &RpcContext, epoch: EpochTime) -> Result<()> {
×
501
    let consensus_epoch = consensus_epoch(ctx)?;
×
502
    if consensus_epoch < epoch || consensus_epoch > epoch + MAX_EPHEMERAL_KEY_AGE {
×
503
        return Err(KeyManagerError::InvalidEpoch(consensus_epoch, epoch).into());
×
504
    }
505
    Ok(())
×
506
}
507

508
/// Validate that given height is fresh, i.e. the height is not more than
509
/// predefined number of blocks lower than the height of the latest trust root.
510
///
511
/// Key manager should use this validation to detect whether the runtimes
512
/// querying it have a fresh enough state.
513
fn validate_height_freshness(ctx: &RpcContext, height: Option<u64>) -> Result<()> {
×
514
    // Outdated key manager clients will not send height in their requests.
515
    // To ensure backwards compatibility we skip check in those cases.
516
    // This should be removed in the future by making height mandatory.
517
    if let Some(height) = height {
×
518
        let latest_height = block_on(ctx.consensus_verifier.latest_height())?;
×
519
        if latest_height > MAX_FRESH_HEIGHT_AGE && height < latest_height - MAX_FRESH_HEIGHT_AGE {
×
520
            return Err(KeyManagerError::HeightNotFresh.into());
×
521
        }
522
    }
523
    Ok(())
×
524
}
525

526
/// Verify that the master secret has been published in the consensus layer.
527
fn validate_signed_master_secret(
×
528
    ctx: &RpcContext,
529
    signed_secret: &SignedEncryptedMasterSecret,
530
) -> Result<EncryptedMasterSecret> {
531
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
532
    let km_state = KeyManagerState::new(&consensus_state);
×
533
    let published_signed_secret = km_state
×
534
        .master_secret(signed_secret.secret.runtime_id)?
×
535
        .filter(|published_signed_secret| published_signed_secret == signed_secret)
×
536
        .ok_or(KeyManagerError::MasterSecretNotPublished)?;
×
537

538
    Ok(published_signed_secret.secret)
×
539
}
540

541
/// Validate that the ephemeral secret has been published in the consensus layer.
542
fn validate_signed_ephemeral_secret(
×
543
    ctx: &RpcContext,
544
    signed_secret: &SignedEncryptedEphemeralSecret,
545
) -> Result<EncryptedEphemeralSecret> {
546
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
547
    let km_state = KeyManagerState::new(&consensus_state);
×
548
    let published_signed_secret = km_state
×
549
        .ephemeral_secret(signed_secret.secret.runtime_id)?
×
550
        .filter(|published_signed_secret| published_signed_secret == signed_secret)
×
551
        .ok_or(KeyManagerError::EphemeralSecretNotPublished)?;
×
552

553
    Ok(published_signed_secret.secret)
×
554
}
555

556
/// Fetch the identities of the key manager nodes.
557
fn key_manager_nodes(ctx: &RpcContext, id: Namespace) -> Result<Vec<signature::PublicKey>> {
×
558
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
559
    let km_state = KeyManagerState::new(&consensus_state);
×
560
    let status = km_state
×
561
        .status(id)?
×
562
        .ok_or(KeyManagerError::StatusNotFound)?;
×
563

564
    Ok(status.nodes)
×
565
}
566

567
/// Fetch REK keys of the key manager enclaves from the consensus layer.
568
fn key_manager_rek_keys(
×
569
    ctx: &RpcContext,
570
    id: Namespace,
571
) -> Result<HashMap<signature::PublicKey, x25519::PublicKey>> {
572
    let nodes = key_manager_nodes(ctx, id)?;
×
573

574
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
575
    let registry_state = RegistryState::new(&consensus_state);
×
576

577
    let mut rek_map = HashMap::new();
×
578
    for pk in nodes.iter() {
×
579
        let node = registry_state.node(pk)?;
×
580
        let runtimes = node
×
581
            .map(|n| n.runtimes)
×
582
            .unwrap_or_default()
583
            .unwrap_or_default();
584
        // Skipping version check as key managers are running exactly one version of the runtime.
585
        let runtime = runtimes.iter().find(|nr| nr.id == id);
×
586

587
        // In an SGX environment we use REK key from the consensus layer.
588
        #[cfg(target_env = "sgx")]
589
        let rek = runtime
590
            .map(|nr| nr.capabilities.tee.as_ref())
591
            .unwrap_or_default()
592
            .map(|c| c.rek)
593
            .unwrap_or_default();
594

595
        // Otherwise we use the same insecure REK key for all enclaves.
596
        #[cfg(not(target_env = "sgx"))]
597
        let rek = runtime.map(|_| ctx.identity.public_rek());
×
598

599
        if let Some(rek) = rek {
×
600
            rek_map.insert(*pk, rek);
×
601
        }
602
    }
603

604
    Ok(rek_map)
×
605
}
606

607
/// Fetch the identities of the key manager nodes that can decrypt the given ephemeral secret.
608
fn nodes_with_ephemeral_secret(
×
609
    ctx: &RpcContext,
610
    secret: &EncryptedEphemeralSecret,
611
) -> Result<Vec<signature::PublicKey>> {
612
    let rek_keys = key_manager_rek_keys(ctx, secret.runtime_id)?;
×
613
    let nodes = rek_keys
×
614
        .iter()
615
        .filter(|(_, rek)| secret.secret.ciphertexts.contains_key(rek))
×
616
        .map(|(&node, _)| node)
×
617
        .collect();
618

619
    Ok(nodes)
×
620
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc