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

oasisprotocol / oasis-core / #4588

07 Mar 2024 09:50AM UTC coverage: 44.999% (-0.02%) from 45.016%
#4588

push

web-flow
Merge pull request #5587 from oasisprotocol/ptrus/stable/23.0.x/go-1.21.8

[stable/23.0.x] go: update to 1.21.8

3 of 4 new or added lines in 2 files covered. (75.0%)

41 existing lines in 19 files now uncovered.

2857 of 6349 relevant lines covered (45.0%)

0.96 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: &mut 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

74
    // Note that the first validation of the status will probably fail,
75
    // as the verifier is one block behind the consensus.
76
    let status = req.status.clone();
×
77
    let status = validate_key_manager_status(ctx, runtime_id, status)?;
×
78

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

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

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

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

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

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

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

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

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

136
    Kdf::global().get_or_create_ephemeral_keys(req.runtime_id, req.key_pair_id, req.epoch)
×
137
}
138

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

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

152
    // Outdated key manager clients request public ephemeral keys via secure RPC calls,
153
    // they never verify their signatures and are not aware that signed ephemeral keys expire.
154
    // To ensure backwards compatibility we clear the expiration epoch. This should be removed
155
    // in the future once all clients are upgraded.
156
    // XXX: Remove this after 23.0.x.
157
    if ctx.is_secure {
×
158
        sig.expiration = None;
×
159
    }
160

161
    Ok(sig)
×
162
}
163

164
/// See `Kdf::replicate_master_secret`.
165
pub fn replicate_master_secret(
×
166
    ctx: &mut RpcContext,
167
    req: &ReplicateMasterSecretRequest,
168
) -> Result<ReplicateMasterSecretResponse> {
169
    authorize_secret_replication(ctx)?;
×
170
    validate_height_freshness(ctx, req.height)?;
×
171

172
    let master_secret =
×
173
        Kdf::global().replicate_master_secret(ctx.untrusted_local_storage, req.generation)?;
174
    let checksum = Kdf::load_checksum(ctx.untrusted_local_storage, req.generation);
×
175

176
    Ok(ReplicateMasterSecretResponse {
×
177
        master_secret,
×
178
        checksum,
179
    })
180
}
181

182
/// See `Kdf::replicate_ephemeral_secret`.
183
pub fn replicate_ephemeral_secret(
×
184
    ctx: &mut RpcContext,
185
    req: &ReplicateEphemeralSecretRequest,
186
) -> Result<ReplicateEphemeralSecretResponse> {
187
    authorize_secret_replication(ctx)?;
×
188
    validate_height_freshness(ctx, req.height)?;
×
189

190
    let ephemeral_secret = Kdf::global().replicate_ephemeral_secret(req.epoch)?;
×
191
    Ok(ReplicateEphemeralSecretResponse { ephemeral_secret })
×
192
}
193

194
/// Generate a master secret and encrypt it using the key manager's REK keys.
195
pub fn generate_master_secret(
×
196
    ctx: &mut RpcContext,
197
    req: &GenerateMasterSecretRequest,
198
) -> Result<GenerateMasterSecretResponse> {
199
    let kdf = Kdf::global();
×
200
    let runtime_id = kdf.runtime_id()?;
×
201

202
    // Allow generating a secret for the next epoch only.
203
    let epoch = consensus_epoch(ctx)? + 1;
×
204
    if epoch != req.epoch {
×
205
        return Err(KeyManagerError::InvalidEpoch(epoch, req.epoch).into());
×
206
    }
207

208
    // Generate a secret and encrypt it.
209
    // Note that the checksum can be computed for the next generation only.
210
    let generation = req.generation;
×
211
    let secret = Secret::generate();
×
212
    let checksum = kdf.checksum_master_secret_proposal(runtime_id, &secret, generation)?;
×
213
    let additional_data = pack_runtime_id_generation_epoch(&runtime_id, generation, epoch);
×
214
    let secret = encrypt_secret(ctx, secret, checksum, additional_data, runtime_id)?;
×
215

216
    // Sign the secret.
217
    let signer: Arc<dyn Signer> = ctx.identity.clone();
×
218
    let secret = EncryptedMasterSecret {
219
        runtime_id,
220
        generation,
221
        epoch,
222
        secret,
223
    };
224
    let signed_secret = SignedEncryptedMasterSecret::new(secret, &signer)?;
×
225

226
    Ok(GenerateMasterSecretResponse { signed_secret })
×
227
}
228

229
/// Generate an ephemeral secret and encrypt it using the key manager's REK keys.
230
pub fn generate_ephemeral_secret(
×
231
    ctx: &mut RpcContext,
232
    req: &GenerateEphemeralSecretRequest,
233
) -> Result<GenerateEphemeralSecretResponse> {
234
    let kdf = Kdf::global();
×
235
    let runtime_id = kdf.runtime_id()?;
×
236

237
    // Allow generating a secret for the next epoch only.
238
    let epoch = consensus_epoch(ctx)? + 1;
×
239
    if epoch != req.epoch {
×
240
        return Err(KeyManagerError::InvalidEpoch(epoch, req.epoch).into());
×
241
    }
242

243
    // Generate a secret and encrypt it.
244
    let secret = Secret::generate();
×
245
    let checksum = Kdf::checksum_ephemeral_secret(&runtime_id, &secret, epoch);
×
246
    let additional_data = pack_runtime_id_epoch(&runtime_id, epoch);
×
247
    let secret = encrypt_secret(ctx, secret, checksum, additional_data, runtime_id)?;
×
248

249
    // Sign the secret.
250
    let signer: Arc<dyn Signer> = ctx.identity.clone();
×
251
    let secret = EncryptedEphemeralSecret {
252
        runtime_id,
253
        epoch,
254
        secret,
255
    };
256
    let signed_secret = SignedEncryptedEphemeralSecret::new(secret, &signer)?;
×
257

258
    Ok(GenerateEphemeralSecretResponse { signed_secret })
×
259
}
260

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

285
        let mut ciphertext = deoxysii::box_seal(
286
            &nonce,
×
287
            plaintext.clone(),
×
288
            additional_data.clone(),
×
289
            &rek.0,
290
            &priv_key.0,
291
        )?;
292
        ciphertext.extend_from_slice(&nonce.to_vec());
×
293

294
        ciphertexts.insert(*rek, ciphertext);
×
295
    }
296

297
    Ok(EncryptedSecret {
×
298
        checksum,
×
299
        pub_key,
300
        ciphertexts,
×
301
    })
302
}
303

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

308
    let secret = match decrypt_master_secret(ctx, &signed_secret)? {
×
309
        Some(secret) => secret,
×
310
        None => return Ok(()),
×
311
    };
312

313
    Kdf::global().add_master_secret_proposal(
×
314
        ctx.untrusted_local_storage,
×
UNCOV
315
        &signed_secret.runtime_id,
×
316
        secret,
×
317
        signed_secret.generation,
×
318
        &signed_secret.secret.checksum,
319
    )
320
}
321

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

327
    let secret = match decrypt_ephemeral_secret(ctx, &signed_secret)? {
×
328
        Some(secret) => secret,
×
329
        None => {
330
            let nodes = nodes_with_ephemeral_secret(ctx, &signed_secret)?;
×
331
            let client = key_manager_client_for_replication(ctx);
×
332

333
            KeyManagerSecretProvider::new(client, nodes)
×
334
                .ephemeral_secret_iter(signed_secret.epoch)
×
335
                .find(|secret| {
×
336
                    let checksum = Kdf::checksum_ephemeral_secret(
×
337
                        &signed_secret.runtime_id,
×
338
                        secret,
339
                        signed_secret.epoch,
×
340
                    );
341
                    checksum == signed_secret.secret.checksum
×
342
                })
343
                .ok_or(KeyManagerError::EphemeralSecretNotReplicated(
×
344
                    signed_secret.epoch,
×
345
                ))?
346
        }
347
    };
348

349
    Kdf::global().add_ephemeral_secret(
×
UNCOV
350
        &signed_secret.runtime_id,
×
351
        secret,
×
352
        signed_secret.epoch,
×
353
        &signed_secret.secret.checksum,
354
    )
355
}
356

357
/// Decrypt master secret with local REK key.
358
fn decrypt_master_secret(
×
359
    ctx: &mut RpcContext,
360
    secret: &EncryptedMasterSecret,
361
) -> Result<Option<Secret>> {
362
    let generation = secret.generation;
×
363
    let epoch = secret.epoch;
×
364
    let runtime_id = secret.runtime_id;
×
365
    let rek = ctx.identity.public_rek();
×
366

367
    let ciphertext = match secret.secret.ciphertexts.get(&rek) {
×
368
        Some(ciphertext) => ciphertext,
×
369
        None => return Ok(None),
×
370
    };
371

372
    let (ciphertext, nonce) =
×
373
        unpack_encrypted_secret_nonce(ciphertext).ok_or(KeyManagerError::InvalidCiphertext)?;
374
    let additional_data = pack_runtime_id_generation_epoch(&runtime_id, generation, epoch);
×
375
    let plaintext = ctx.identity.box_open(
×
376
        &nonce,
377
        ciphertext,
×
378
        additional_data,
×
379
        &secret.secret.pub_key.0,
×
380
    )?;
381

382
    if plaintext.len() != SECRET_SIZE {
×
383
        return Err(KeyManagerError::InvalidCiphertext.into());
×
384
    }
385

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

388
    Ok(Some(secret))
×
389
}
390

391
/// Decrypt ephemeral secret with local REK key.
392
fn decrypt_ephemeral_secret(
×
393
    ctx: &mut RpcContext,
394
    secret: &EncryptedEphemeralSecret,
395
) -> Result<Option<Secret>> {
396
    let epoch = secret.epoch;
×
397
    let runtime_id = secret.runtime_id;
×
398
    let rek = ctx.identity.public_rek();
×
399

400
    let ciphertext = match secret.secret.ciphertexts.get(&rek) {
×
401
        Some(ciphertext) => ciphertext,
×
402
        None => return Ok(None),
×
403
    };
404

405
    let (ciphertext, nonce) =
×
406
        unpack_encrypted_secret_nonce(ciphertext).ok_or(KeyManagerError::InvalidCiphertext)?;
407
    let additional_data = pack_runtime_id_epoch(&runtime_id, epoch);
×
408
    let plaintext = ctx.identity.box_open(
×
409
        &nonce,
410
        ciphertext,
×
411
        additional_data,
×
412
        &secret.secret.pub_key.0,
×
413
    )?;
414

415
    if plaintext.len() != SECRET_SIZE {
×
416
        return Err(KeyManagerError::InvalidCiphertext.into());
×
417
    }
418

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

421
    Ok(Some(secret))
×
422
}
423

424
/// Key manager client for master and ephemeral secret replication.
425
fn key_manager_client_for_replication(ctx: &mut RpcContext) -> RemoteClient {
×
426
    let rctx = runtime_context!(ctx, KmContext);
×
427
    let protocol = rctx.protocol.clone();
×
428
    let runtime_id = rctx.runtime_id;
×
429

430
    RemoteClient::new_runtime_with_enclaves_and_policy(
431
        runtime_id,
432
        Some(runtime_id),
×
433
        Policy::global().may_replicate_from(),
×
434
        ctx.identity.quote_policy(),
×
435
        protocol,
×
436
        ctx.consensus_verifier.clone(),
×
437
        ctx.identity.clone(),
×
438
        1, // Not used, doesn't matter.
439
        vec![],
×
440
    )
441
}
442

443
/// Create init response and sign it with RAK.
444
fn sign_init_response(
×
445
    ctx: &mut RpcContext,
446
    state: State,
447
    policy_checksum: Vec<u8>,
448
) -> Result<SignedInitResponse> {
449
    let is_secure = BUILD_INFO.is_secure && !Policy::unsafe_skip();
×
450
    let init_response = InitResponse {
451
        is_secure,
452
        checksum: state.checksum,
×
453
        next_checksum: state.next_checksum,
×
454
        policy_checksum,
455
        rsk: state.signing_key,
×
456
        next_rsk: state.next_signing_key,
×
457
    };
458
    let signer: Arc<dyn Signer> = ctx.identity.clone();
×
459
    SignedInitResponse::new(init_response, &signer)
×
460
}
461

462
/// Authorize the remote enclave so that the private keys are never released to an incorrect enclave.
463
fn authorize_private_key_generation(ctx: &RpcContext, runtime_id: &Namespace) -> Result<()> {
×
464
    if Policy::unsafe_skip() {
×
465
        return Ok(()); // Authorize unsafe builds always.
×
466
    }
467
    let remote_enclave = authenticate(ctx)?;
×
468
    Policy::global().may_get_or_create_keys(remote_enclave, runtime_id)
×
469
}
470

471
/// Authorize the remote enclave so that the master and ephemeral secrets are never replicated
472
/// to an incorrect enclave.
473
fn authorize_secret_replication(ctx: &RpcContext) -> Result<()> {
×
474
    if Policy::unsafe_skip() {
×
475
        return Ok(()); // Authorize unsafe builds always.
×
476
    }
477
    let remote_enclave = authenticate(ctx)?;
×
478
    Policy::global().may_replicate_secret(remote_enclave)
×
479
}
480

481
/// Authenticate the remote enclave based on the MRSIGNER/MRENCLAVE/request.
482
fn authenticate<'a>(ctx: &'a RpcContext) -> Result<&'a EnclaveIdentity> {
×
483
    let si = ctx.session_info.as_ref();
×
484
    let si = si.ok_or(KeyManagerError::NotAuthenticated)?;
×
485
    Ok(&si.verified_quote.identity)
×
486
}
487

488
/// Fetch current epoch from the consensus layer.
489
fn consensus_epoch(ctx: &RpcContext) -> Result<EpochTime> {
×
490
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
491
    let beacon_state = BeaconState::new(&consensus_state);
×
492
    let consensus_epoch = beacon_state.epoch()?;
×
493

494
    Ok(consensus_epoch)
×
495
}
496

497
/// Verify that the key manager status has been published in the consensus layer.
498
fn validate_key_manager_status(
×
499
    ctx: &RpcContext,
500
    runtime_id: Namespace,
501
    status: Status,
502
) -> Result<Status> {
503
    let consensus_verifier = ctx.consensus_verifier.clone();
×
504
    let verifier = PolicyVerifier::new(consensus_verifier);
×
505

506
    verifier.verify_key_manager_status(status, runtime_id)
×
507
}
508

509
/// Validate that the epoch used for derivation of ephemeral private keys is not
510
/// in the future or too far back in the past.
511
fn validate_ephemeral_key_epoch(ctx: &RpcContext, epoch: EpochTime) -> Result<()> {
×
512
    let consensus_epoch = consensus_epoch(ctx)?;
×
513
    if consensus_epoch < epoch || consensus_epoch > epoch + MAX_EPHEMERAL_KEY_AGE {
×
514
        return Err(KeyManagerError::InvalidEpoch(consensus_epoch, epoch).into());
×
515
    }
516
    Ok(())
×
517
}
518

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

537
/// Verify that the master secret has been published in the consensus layer.
538
fn validate_signed_master_secret(
×
539
    ctx: &RpcContext,
540
    signed_secret: &SignedEncryptedMasterSecret,
541
) -> Result<EncryptedMasterSecret> {
542
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
543
    let km_state = KeyManagerState::new(&consensus_state);
×
544
    let published_signed_secret = km_state
×
545
        .master_secret(signed_secret.secret.runtime_id)?
×
546
        .filter(|published_signed_secret| published_signed_secret == signed_secret)
×
547
        .ok_or(KeyManagerError::MasterSecretNotPublished)?;
×
548

549
    Ok(published_signed_secret.secret)
×
550
}
551

552
/// Validate that the ephemeral secret has been published in the consensus layer.
553
fn validate_signed_ephemeral_secret(
×
554
    ctx: &RpcContext,
555
    signed_secret: &SignedEncryptedEphemeralSecret,
556
) -> Result<EncryptedEphemeralSecret> {
557
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
558
    let km_state = KeyManagerState::new(&consensus_state);
×
559
    let published_signed_secret = km_state
×
560
        .ephemeral_secret(signed_secret.secret.runtime_id)?
×
561
        .filter(|published_signed_secret| published_signed_secret == signed_secret)
×
562
        .ok_or(KeyManagerError::EphemeralSecretNotPublished)?;
×
563

564
    Ok(published_signed_secret.secret)
×
565
}
566

567
/// Fetch the identities of the key manager nodes.
568
fn key_manager_nodes(ctx: &RpcContext, id: Namespace) -> Result<Vec<signature::PublicKey>> {
×
569
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
570
    let km_state = KeyManagerState::new(&consensus_state);
×
571
    let status = km_state
×
572
        .status(id)?
×
573
        .ok_or(KeyManagerError::StatusNotFound)?;
×
574

575
    Ok(status.nodes)
×
576
}
577

578
/// Fetch REK keys of the key manager enclaves from the consensus layer.
579
fn key_manager_rek_keys(
×
580
    ctx: &RpcContext,
581
    id: Namespace,
582
) -> Result<HashMap<signature::PublicKey, x25519::PublicKey>> {
583
    let nodes = key_manager_nodes(ctx, id)?;
×
584

585
    let consensus_state = block_on(ctx.consensus_verifier.latest_state())?;
×
586
    let registry_state = RegistryState::new(&consensus_state);
×
587

588
    let mut rek_map = HashMap::new();
×
589
    for pk in nodes.iter() {
×
590
        let node = registry_state.node(pk)?;
×
591
        let runtimes = node
×
592
            .map(|n| n.runtimes)
×
593
            .unwrap_or_default()
594
            .unwrap_or_default();
595
        // Skipping version check as key managers are running exactly one version of the runtime.
596
        let runtime = runtimes.iter().find(|nr| nr.id == id);
×
597

598
        // In an SGX environment we use REK key from the consensus layer.
599
        #[cfg(target_env = "sgx")]
600
        let rek = runtime
601
            .map(|nr| nr.capabilities.tee.as_ref())
602
            .unwrap_or_default()
603
            .map(|c| c.rek)
604
            .unwrap_or_default();
605

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

610
        if let Some(rek) = rek {
×
611
            rek_map.insert(*pk, rek);
×
612
        }
613
    }
614

615
    Ok(rek_map)
×
616
}
617

618
/// Fetch the identities of the key manager nodes that can decrypt the given ephemeral secret.
619
fn nodes_with_ephemeral_secret(
×
620
    ctx: &RpcContext,
621
    secret: &EncryptedEphemeralSecret,
622
) -> Result<Vec<signature::PublicKey>> {
623
    let rek_keys = key_manager_rek_keys(ctx, secret.runtime_id)?;
×
624
    let nodes = rek_keys
×
625
        .iter()
626
        .filter(|(_, rek)| secret.secret.ciphertexts.contains_key(rek))
×
627
        .map(|(&node, _)| node)
×
628
        .collect();
629

630
    Ok(nodes)
×
631
}
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