1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Exceptions;
13 using Antmicro.Renode.Peripherals.MemoryControllers;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Utilities;
16 using Org.BouncyCastle.Crypto.Macs;
17 using Org.BouncyCastle.Crypto.Parameters;
18 
19 namespace Antmicro.Renode.Peripherals.Miscellaneous
20 {
21     public class OpenTitan_KeyManager : BasicDoubleWordPeripheral, IKnownSize
22     {
OpenTitan_KeyManager(IMachine machine, OpenTitan_ROMController romController, string deviceId, string lifeCycleDiversificationConstant, string creatorKey, string ownerKey, string rootKey, string softOutputSeed, string hardOutputSeed, string destinationNoneSeed, string destinationAesSeed, string destinationOtbnSeed, string destinationKmacSeed, string revisionSeed, string creatorIdentitySeed, string ownerIntermediateIdentitySeed, string ownerIdentitySeed, bool kmacEnableMasking = true, int randomSeed = 0, ISideloadableKey kmac = null, ISideloadableKey aes = null, ISideloadableKey otbn = null)23         public OpenTitan_KeyManager(IMachine machine, OpenTitan_ROMController romController,
24             string deviceId, string lifeCycleDiversificationConstant, string creatorKey, string ownerKey, string rootKey,
25             string softOutputSeed, string hardOutputSeed, string destinationNoneSeed, string destinationAesSeed, string destinationOtbnSeed, string destinationKmacSeed,
26             string revisionSeed, string creatorIdentitySeed, string ownerIntermediateIdentitySeed, string ownerIdentitySeed,
27             bool kmacEnableMasking = true, int randomSeed = 0, ISideloadableKey kmac = null, ISideloadableKey aes = null, ISideloadableKey otbn = null) : base(machine)
28         {
29             this.romController = romController;
30             destinations = new Dictionary<Destination, ISideloadableKey>();
31             if(kmac != null)
32             {
33                 destinations.Add(Destination.KMAC, kmac);
34             }
35             if(aes != null)
36             {
37                 destinations.Add(Destination.AES, aes);
38             }
39             if(otbn != null)
40             {
41                 destinations.Add(Destination.OTBN, otbn);
42             }
43             OperationDoneIRQ = new GPIO();
44             FatalAlert = new GPIO();
45             RecoverableAlert = new GPIO();
46 
47             random = new Random(randomSeed);
48             sealingSoftwareBinding = new byte[MultiRegistersCount * 4];
49             attestationSoftwareBinding = new byte[MultiRegistersCount * 4];
50             salt = new byte[MultiRegistersCount * 4];
51             softwareShareOutput = new byte[MultiRegistersCount * 4 * NumberOfSoftwareShareOutputs];
52 
53             this.deviceId = ConstructorParseHexstringArgument("deviceId", deviceId, DeviceIdExpectedLength); // OTP_HW_CFG_DATA_DEFAULT.device_id
54             this.lifeCycleDiversificationConstant = ConstructorParseHexstringArgument("lifeCycleDiversificationConstant", lifeCycleDiversificationConstant, LifeCycleDiversificationConstantLength); // RndCnstLcKeymgrDiv
55             this.creatorKey = ConstructorParseHexstringArgument("creatorKey", creatorKey, CreatorKeyExpectedLength); // KEYMGR_FLASH_DEFAULT.seeds[CreatorSeedIdx]
56             this.ownerKey = ConstructorParseHexstringArgument("ownerKey", ownerKey, OwnerKeyExpectedLength); // KEYMGR_FLASH_DEFAULT.seeds[OwnerSeedIdx]
57             var rootKeyTemp = ConstructorParseHexstringArgument("rootKey", rootKey, RootKeyExpectedLength); // OTP_KEYMGR_KEY_DEFAULT
58             // If `KmacEnMasking` is set then key is composed of both shares,
59             // otherwise the first key share is a xor of shares and the second key share is zero
60             if(kmacEnableMasking)
61             {
62                 this.rootKey = rootKeyTemp;
63             }
64             else
65             {
66                 this.rootKey = rootKeyTemp
67                     .Take(rootKeyTemp.Length / 2)
68                     .Zip(rootKeyTemp.Skip(rootKeyTemp.Length / 2), (b0, b1) => (byte)(b0 ^ b1))
69                     .Concat(Enumerable.Repeat((byte)0, rootKeyTemp.Length / 2))
70                     .ToArray();
71             }
72             this.softOutputSeed = ConstructorParseHexstringArgument("softOutputSeed", softOutputSeed, SeedExpectedLength); // RndCnstSoftOutputSeed
73             this.hardOutputSeed = ConstructorParseHexstringArgument("hardOutputSeed", hardOutputSeed, SeedExpectedLength); // RndCnstHardOutputSeed
74             this.destinationNoneSeed = ConstructorParseHexstringArgument("destinationNoneSeed", destinationNoneSeed, SeedExpectedLength); // RndCnstAesSeed
75             this.destinationAesSeed = ConstructorParseHexstringArgument("destinationAesSeed", destinationAesSeed, SeedExpectedLength); // RndCnstKmacSeed
76             this.destinationOtbnSeed = ConstructorParseHexstringArgument("destinationOtbnSeed", destinationOtbnSeed, SeedExpectedLength); // RndCnstOtbnSeed
77             this.destinationKmacSeed = ConstructorParseHexstringArgument("destinationKmacSeed", destinationKmacSeed, SeedExpectedLength); // RndCnstNoneSeed
78             this.revisionSeed = ConstructorParseHexstringArgument("revisionSeed", revisionSeed, SeedExpectedLength); // RndCnstRevisionSeed
79             this.creatorIdentitySeed = ConstructorParseHexstringArgument("creatorIdentitySeed", creatorIdentitySeed, SeedExpectedLength); // RndCnstCreatorIdentitySeed
80             this.ownerIntermediateIdentitySeed = ConstructorParseHexstringArgument("ownerIntermediateIdentitySeed", ownerIntermediateIdentitySeed, SeedExpectedLength); // RndCnstOwnerIntIdentitySeed
81             this.ownerIdentitySeed = ConstructorParseHexstringArgument("ownerIdentitySeed", ownerIdentitySeed, SeedExpectedLength); // RndCnstOwnerIdentitySeed
82 
83             DefineRegisters();
84             Reset();
85         }
86 
Reset()87         public override void Reset()
88         {
89             base.Reset();
90 
91             FatalAlert.Unset();
92             RecoverableAlert.Unset();
93             Array.Clear(sealingSoftwareBinding, 0, sealingSoftwareBinding.Length);
94             Array.Clear(attestationSoftwareBinding, 0, attestationSoftwareBinding.Length);
95             Array.Clear(salt, 0, salt.Length);
96             Array.Clear(softwareShareOutput, 0, softwareShareOutput.Length);
97         }
98 
99         public long Size => 0x1000;
100 
101         public GPIO OperationDoneIRQ { get; }
102 
103         public GPIO FatalAlert { get; }
104         public GPIO RecoverableAlert { get; }
105 
ConstructorParseHexstringArgument(string fieldName, string value, int expectedLength)106         static private byte[] ConstructorParseHexstringArgument(string fieldName, string value, int expectedLength)
107         {
108             byte[] field;
109             var lengthInBytes = value.Length / 2;
110             if(lengthInBytes != expectedLength)
111             {
112                 throw new ConstructionException($"Expected `{fieldName}`'s size is {expectedLength} bytes, got {lengthInBytes}");
113             }
114             try
115             {
116                 field = Misc.HexStringToByteArray(value);
117             }
118             catch
119             {
120                 throw new ConstructionException($"Could not parse `{fieldName}`: Expected hexstring, got: \"{value}\"");
121             }
122             return field;
123         }
124 
125         private static WorkingState[] IllegalForAdvance = { WorkingState.Invalid, WorkingState.Disabled };
126         private static WorkingState[] IllegalForDisable = { WorkingState.Invalid, WorkingState.Disabled };
127         private static WorkingState[] IllegalForGenerate = { WorkingState.Invalid, WorkingState.Disabled, WorkingState.Init };
128 
RunCommand()129         private void RunCommand()
130         {
131             var command = operationMode.Value;
132             this.Log(LogLevel.Debug, "Received command: {0}", command);
133             if(state.Value == WorkingState.Reset && command != OperationMode.Advance)
134             {
135                 // In the Reset state no other commands are allowed
136                 this.Log(LogLevel.Warning, "Ignoring command {0} in the reset state", command);
137                 return;
138             }
139 
140             switch(command)
141             {
142                 case OperationMode.Advance:
143                     if(CheckLegality(IllegalForAdvance))
144                     {
145                         AdvanceState();
146                     }
147                     break;
148                 case OperationMode.GenerateID:
149                     if(CheckLegality(IllegalForGenerate))
150                     {
151                         softwareShareOutput = CalculateKMAC(IdentitySeed, softwareShareOutput.Length);
152                     }
153                     break;
154                 case OperationMode.GenerateHWOutput:
155                     if(CheckLegality(IllegalForGenerate) && CheckKeyVersion())
156                     {
157                         var data = BitConverter.GetBytes((uint)keyVersion.Value)
158                             .Concat(salt)
159                             .Concat(DestinationCipherSeed)
160                             .Concat(hardOutputSeed);
161                         var length = destination.Value == Destination.OTBN ? SideloadKeyLengthOTBN : SideloadKeyLength;
162                         var output = CalculateKMAC(data, length);
163                         if(destinations.TryGetValue(destination.Value, out var dest))
164                         {
165                             dest.SideloadKey = output;
166                         }
167                         else
168                         {
169                             this.Log(LogLevel.Warning, "Sideload key for {0} is not possible, peripheral is not specified", destination.Value);
170                         }
171                     }
172                     break;
173                 case OperationMode.GenerateSWOutput:
174                     if(CheckLegality(IllegalForGenerate) && CheckKeyVersion())
175                     {
176                         var data = BitConverter.GetBytes((uint)keyVersion.Value)
177                             .Concat(salt)
178                             .Concat(DestinationCipherSeed)
179                             .Concat(softOutputSeed);
180                         softwareShareOutput = CalculateKMAC(data, softwareShareOutput.Length);
181                     }
182                     break;
183                 case OperationMode.Disable:
184                     if(CheckLegality(IllegalForDisable))
185                     {
186                         state.Value = WorkingState.Disabled;
187                     }
188                     break;
189                 default:
190                     this.Log(LogLevel.Warning, "Unsupported {0} operation", state.Value);
191                     break;
192             }
193         }
194 
CheckLegality(WorkingState[] illegalStates)195         private bool CheckLegality(WorkingState[] illegalStates)
196         {
197             if(illegalStates.Contains(state.Value))
198             {
199                 HandleIllegalOperation();
200                 return false;
201             }
202             return true;
203         }
204 
CheckKeyVersion()205         private bool CheckKeyVersion()
206         {
207             if(keyVersion.Value > MaxKeyVersion)
208             {
209                 invalidKmacInputFlag.Value = true;
210                 return false;
211             }
212             return true;
213         }
214 
Invalidate()215         private void Invalidate()
216         {
217             var key = new byte[SideloadKeyLength];
218             foreach(var dest in destinations.Values)
219             {
220                 random.NextBytes(key);
221                 dest.SideloadKey = key;
222             }
223             random.NextBytes(softwareShareOutput);
224         }
225 
HandleIllegalOperation()226         private void HandleIllegalOperation()
227         {
228             status.Value = Status.DoneError;
229             invalidOperationFlag.Value = true;
230         }
231 
AdvanceState()232         private void AdvanceState()
233         {
234             IEnumerable<byte> data;
235 
236             switch(state.Value)
237             {
238                 case WorkingState.Reset:
239                     state.Value++;
240                     internalKey = rootKey;
241                     break;
242                 case WorkingState.Init:
243                     state.Value++;
244                     data = SoftwareBinding
245                         .Concat(revisionSeed)
246                         .Concat(deviceId)
247                         .Concat(lifeCycleDiversificationConstant)
248                         .Concat(romController.Digest)
249                         .Concat(creatorKey);
250                     creatorRootStateKey = CalculateKMAC(data, RootKeyExpectedLength);
251                     internalKey = creatorRootStateKey;
252                     break;
253                 case WorkingState.CreatorRootKey:
254                     state.Value++;
255                     data = SoftwareBinding
256                         .Concat(ownerKey);
257                     ownerIntermediateStateKey = CalculateKMAC(data, RootKeyExpectedLength);
258                     internalKey = ownerIntermediateStateKey;
259                     break;
260                 case WorkingState.OwnerIntermediateKey:
261                     state.Value++;
262                     data = SoftwareBinding;
263                     ownerStateKey = CalculateKMAC(data, RootKeyExpectedLength);
264                     internalKey = ownerStateKey;
265                     break;
266                 case WorkingState.OwnerKey:
267                     state.Value++;
268                     break;
269                 case WorkingState.Disabled:
270                     Invalidate();
271                     break;
272                 case WorkingState.Invalid:
273                     // This is a proper state, no additonal logging is required
274                     break;
275                 default:
276                     this.Log(LogLevel.Warning, "Reached unexpected state: {0}", state.Value);
277                     break;
278             }
279 
280             this.Log(LogLevel.Debug, "WorkingState advanced to '{0}'", state.Value);
281             status.Value = Status.Idle;
282         }
283 
CalculateKMAC(IEnumerable<byte> data, int outputLength)284         public byte[] CalculateKMAC(IEnumerable<byte> data, int outputLength)
285         {
286             var mac = new KMac(KmacBitLength, null);
287             mac.Init(new KeyParameter(internalKey));
288             var dataArray = data.ToArray();
289             mac.BlockUpdate(dataArray, 0, dataArray.Length);
290             var output = new byte[outputLength];
291             mac.DoFinal(output, 0, outputLength);
292             return output;
293         }
294 
DefineRegisters()295         private void DefineRegisters()
296         {
297             Registers.InterruptState.Define(this)
298                 .WithFlag(0, out interruptStatusOperationDone, FieldMode.Read | FieldMode.WriteOneToClear, name: "op_done")
299                 .WithIgnoredBits(1, 31)
300                 .WithWriteCallback((_, __) => UpdateInterrupts());
301 
302             Registers.InterruptEnable.Define(this)
303                 .WithFlag(0, out interruptEnableOperationDone, name: "op_done")
304                 .WithIgnoredBits(1, 31)
305                 .WithWriteCallback((_, __) => UpdateInterrupts());
306 
307             Registers.InterruptTest.Define(this)
308                 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { interruptStatusOperationDone.Value |= val; }, name: "op_done")
309                 .WithIgnoredBits(1, 31)
310                 .WithWriteCallback((_, __) => UpdateInterrupts());
311 
312             Registers.AlertTest.Define(this)
313                 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) RecoverableAlert.Blink(); }, name: "recov_operation_err") // FieldMode.Write
314                 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault_err") // FieldMode.Write
315                 .WithIgnoredBits(2, 30);
316 
317             Registers.ConfigurationWriteEnable.Define(this, 0x1)
318                 .WithTaggedFlag("EN", 0)   // FieldMode.Read
319                 .WithIgnoredBits(1, 31);
320 
321             Registers.OperationControls.Define(this)
322                 .WithFlag(0, writeCallback: (_, val) => { if (val) RunCommand(); }, valueProviderCallback: _ => false, name: "START")
323                 .WithReservedBits(1, 3)
324                 .WithEnumField<DoubleWordRegister, OperationMode>(4, 3, out operationMode, name: "OPERATION")
325                 .WithEnumField<DoubleWordRegister, CDISetting>(7, 1, out cdiSetting, name: "CDI_SEL")
326                 .WithReservedBits(8, 4)
327                 .WithEnumField<DoubleWordRegister, Destination>(12, 3, out destination, name: "DEST_SEL")
328                 .WithIgnoredBits(15, 17)
329                 .WithWriteCallback((_, __) => UpdateInterrupts());
330 
331             Registers.SideloadClear.Define(this)
332                 .WithTag("VAL", 0, 3)
333                 .WithIgnoredBits(3, 29);
334 
335             Registers.ReseedIntervalWriteEnable.Define(this, 0x1)
336                 .WithTaggedFlag("EN", 0) // FieldMode.Read | FieldMode.WriteZeroToClear
337                 .WithReservedBits(1, 31);
338 
339             Registers.ReseedInterval.Define(this, 0x100)
340                 .WithValueField(0, 32, out entropyReseedInterval, name: "VAL");
341 
342             Registers.SoftwareBindingWriteEnable.Define(this, 0x1)
343                 .WithTaggedFlag("EN", 0) // FieldMode.Read | FieldMode.WriteZeroToClear
344                 .WithIgnoredBits(1, 31);
345 
346             Registers.SealingSoftwareBinding0.DefineMany(this, MultiRegistersCount, (register, idx) =>
347             {
348                 register.WithValueField(0, 32, writeCallback: (_, val) => { sealingSoftwareBinding.SetBytesFromValue((uint)val, idx * 4); }, valueProviderCallback: _ => (uint)BitConverter.ToInt32(sealingSoftwareBinding, idx * 4), name: $"VAL_{idx}");
349             });
350 
351             Registers.AttestationSoftwareBinding0.DefineMany(this, MultiRegistersCount, (register, idx) =>
352             {
353                 register.WithValueField(0, 32, writeCallback: (_, val) => { attestationSoftwareBinding.SetBytesFromValue((uint)val, idx * 4); }, valueProviderCallback: _ => (uint)BitConverter.ToInt32(attestationSoftwareBinding, idx * 4), name: $"VAL_{idx}");
354             });
355 
356             Registers.Salt0.DefineMany(this, MultiRegistersCount, (register, idx) =>
357             {
358                 register.WithValueField(0, 32, writeCallback: (_, val) => { salt.SetBytesFromValue((uint)val, idx * 4); }, valueProviderCallback: _ => (uint)BitConverter.ToInt32(salt, idx * 4), name: $"VAL_{idx}");
359             });
360 
361             Registers.KeyVersion.Define(this)
362                 .WithValueField(0, 32, out keyVersion, name: "VAL");
363 
364             Registers.MaxCreatorKeyVersionWriteEnable.Define(this, 0x1)
365                 .WithTaggedFlag("EN", 0) // FieldMode.Read | FieldMode.WriteZeroToClear
366                 .WithIgnoredBits(1, 31);
367 
368             Registers.MaxCreatorKeyVersion.Define(this)
369                 .WithValueField(0, 32, out maxCreatorKeyVersion, name: "VAL");
370 
371             Registers.MaxOwnerIntermediateKeyVersionWriteEnable.Define(this, 0x1)
372                 .WithTaggedFlag("EN", 0) // FieldMode.Read | FieldMode.WriteZeroToClear
373                 .WithIgnoredBits(1, 31);
374 
375             Registers.MaxOwnerIntermediateKeyVersion.Define(this)
376                 .WithValueField(0, 32, out maxOwnerIntermediateKeyVersion, name: "VAL");
377 
378             Registers.MaxOwnerKeyVersionWriteEnable.Define(this, 0x1)
379                 .WithTaggedFlag("EN", 0) // FieldMode.Read | FieldMode.WriteZeroToClear
380                 .WithIgnoredBits(1, 31);
381 
382             Registers.MaxOwnerKeyVersion.Define(this)
383                 .WithValueField(0, 32, out maxOwnerKeyVersion, name: "VAL");
384 
385             for(var i = 0; i < NumberOfSoftwareShareOutputs; ++i)
386             {
387                 var offset = Registers.SoftwareShare1Output0 - Registers.SoftwareShare0Output0;
388                 (Registers.SoftwareShare0Output0 + offset * i).DefineMany(this, MultiRegistersCount, (register, idx) =>
389                 {
390                     register.WithValueField(0, 32, FieldMode.ReadToClear, valueProviderCallback: _ =>
391                     {
392                         var startIndex = i * MultiRegistersCount * 4 + idx * 4;
393                         var value = (uint)BitConverter.ToInt32(softwareShareOutput, startIndex);
394                         softwareShareOutput.SetBytesFromValue(0, startIndex);
395                         return value;
396                     }, name: $"VAL_{idx}");
397                 });
398             }
399 
400             Registers.WorkingState.Define(this)
401                 .WithEnumField<DoubleWordRegister, WorkingState>(0, 3, out state, FieldMode.Read, name: "STATE")
402                 .WithIgnoredBits(3, 29);
403 
404             Registers.Status.Define(this)
405                 .WithEnumField<DoubleWordRegister, Status>(0, 2, out status, FieldMode.Read | FieldMode.WriteOneToClear, name: "STATE")
406                 .WithIgnoredBits(2, 30);
407 
408             Registers.ErrorCode.Define(this)
409                 .WithFlag(0, out invalidOperationFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "INVALID_OP")
410                 .WithFlag(1, out invalidKmacInputFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "INVALID_KMAC_INPUT")
411                 .WithTaggedFlag("INVALID_SHADOW_UPDATE", 2) // FieldMode.Read | FieldMode.WriteOneToClear
412                 .WithIgnoredBits(3, 29);
413 
414             Registers.FaultStatus.Define(this)
415                 .WithTaggedFlag("CMDA", 0)          // FieldMode.Read
416                 .WithTaggedFlag("KMAC_FSM", 1)      // FieldMode.Read
417                 .WithTaggedFlag("KMAC_OPKMAC", 2)   // FieldMode.Read
418                 .WithTaggedFlag("KMAC_OUTKMAC", 3)  // FieldMode.Read
419                 .WithTaggedFlag("REGFILE_INTG", 4)  // FieldMode.Read
420                 .WithTaggedFlag("SHADOW", 5)        // FieldMode.Read
421                 .WithTaggedFlag("CTRL_FSM_INTG", 6) // FieldMode.Read
422                 .WithTaggedFlag("CTRL_FSM_CNT", 7)  // FieldMode.Read
423                 .WithTaggedFlag("RESEED_CNT", 8)    // FieldMode.Read
424                 .WithTaggedFlag("SIDE_CTRL_FSM", 9) // FieldMode.Read
425                 .WithReservedBits(10, 22);
426         }
427 
UpdateInterrupts()428         private void UpdateInterrupts()
429         {
430             OperationDoneIRQ.Set(interruptStatusOperationDone.Value && interruptEnableOperationDone.Value);
431         }
432 
433         private IEnumerable<byte> SoftwareBinding => cdiSetting.Value == CDISetting.Sealing ? sealingSoftwareBinding : attestationSoftwareBinding;
434 
435         private IEnumerable<byte> DestinationCipherSeed
436         {
437             get
438             {
439                 switch(destination.Value)
440                 {
441                     case Destination.None:
442                         return destinationNoneSeed;
443                     case Destination.AES:
444                         return destinationAesSeed;
445                     case Destination.KMAC:
446                         return destinationKmacSeed;
447                     case Destination.OTBN:
448                         return destinationOtbnSeed;
449                     default:
450                         this.Log(LogLevel.Error, "Invalid state, destination's value is 0x{0:X}", destination.Value);
451                         return Enumerable.Empty<byte>();
452                 }
453             }
454         }
455 
456         private IEnumerable<byte> IdentitySeed
457         {
458             get
459             {
460                 switch(state.Value)
461                 {
462                     case WorkingState.CreatorRootKey:
463                         return creatorIdentitySeed;
464                     case WorkingState.OwnerIntermediateKey:
465                         return ownerIntermediateIdentitySeed;
466                     case WorkingState.OwnerKey:
467                     default:
468                         this.Log(LogLevel.Error, "Invalid state for getting `IdentitySeed`, state's value is 0x{0:X}", state.Value);
469                         return Enumerable.Empty<byte>();
470                 }
471             }
472         }
473 
474         private uint MaxKeyVersion
475         {
476             get
477             {
478                 switch(state.Value)
479                 {
480                     case WorkingState.CreatorRootKey:
481                         return (uint)maxCreatorKeyVersion.Value;
482                     case WorkingState.OwnerIntermediateKey:
483                         return (uint)maxOwnerIntermediateKeyVersion.Value;
484                     case WorkingState.OwnerKey:
485                         return (uint)maxOwnerKeyVersion.Value;
486                     default:
487                         this.Log(LogLevel.Error, "Invalid state for getting `MaxKeyVersion`, state's value is 0x{0:X}", state.Value);
488                         return 0;
489                 }
490             }
491         }
492 
493         private IFlagRegisterField interruptStatusOperationDone;
494         private IFlagRegisterField interruptEnableOperationDone;
495         private IEnumRegisterField<CDISetting> cdiSetting;
496         private IEnumRegisterField<Destination> destination;
497         private IEnumRegisterField<OperationMode> operationMode;
498         private IEnumRegisterField<Status> status;
499         private IEnumRegisterField<WorkingState> state;
500         private IFlagRegisterField invalidOperationFlag;
501         private IFlagRegisterField invalidKmacInputFlag;
502         private IValueRegisterField entropyReseedInterval;
503         private IValueRegisterField keyVersion;
504         private IValueRegisterField maxCreatorKeyVersion;
505         private IValueRegisterField maxOwnerIntermediateKeyVersion;
506         private IValueRegisterField maxOwnerKeyVersion;
507         private byte[] creatorRootStateKey;
508         private byte[] ownerIntermediateStateKey;
509         private byte[] ownerStateKey;
510         private byte[] softwareShareOutput;
511         private byte[] internalKey;
512 
513         private readonly byte[] sealingSoftwareBinding;
514         private readonly byte[] attestationSoftwareBinding;
515         private readonly byte[] salt;
516         private readonly byte[] revisionSeed;
517         private readonly byte[] deviceId;
518         private readonly byte[] lifeCycleDiversificationConstant;
519         private readonly byte[] creatorKey;
520         private readonly byte[] ownerKey;
521         private readonly byte[] rootKey;
522         private readonly byte[] softOutputSeed;
523         private readonly byte[] hardOutputSeed;
524         private readonly byte[] destinationNoneSeed;
525         private readonly byte[] destinationAesSeed;
526         private readonly byte[] destinationOtbnSeed;
527         private readonly byte[] destinationKmacSeed;
528         private readonly byte[] creatorIdentitySeed;
529         private readonly byte[] ownerIntermediateIdentitySeed;
530         private readonly byte[] ownerIdentitySeed;
531         private readonly Random random;
532         private readonly OpenTitan_ROMController romController;
533         private readonly Dictionary<Destination, ISideloadableKey> destinations;
534 
535         private const int MultiRegistersCount = 8;
536         private const int KmacBitLength = 256;
537         private const int SeedExpectedLength = 256 / 8;
538         private const int DeviceIdExpectedLength = 256 / 8;
539         private const int LifeCycleDiversificationConstantLength = 128 / 8;
540         private const int CreatorKeyExpectedLength = 256 / 8;
541         private const int OwnerKeyExpectedLength = 256 / 8;
542         private const int RootKeyExpectedLength = 256 * 2 / 8;
543         private const int NumberOfSoftwareShareOutputs = 2;
544         private const int SideloadKeyLength = 256 / 8;
545         private const int SideloadKeyLengthOTBN = 384 / 8;
546 
547         public enum OperationMode
548         {
549             Advance = 0,
550             GenerateID = 1,
551             GenerateSWOutput = 2,
552             GenerateHWOutput = 3,
553             Disable = 4,
554         }
555 
556         public enum WorkingState
557         {
558             Reset = 0,
559             Init = 1,
560             CreatorRootKey = 2,
561             OwnerIntermediateKey = 3,
562             OwnerKey = 4,
563             Disabled = 5,
564             Invalid = 6,
565         }
566 
567         public enum Registers
568         {
569             InterruptState = 0x0,
570             InterruptEnable = 0x4,
571             InterruptTest = 0x8,
572             AlertTest = 0xc,
573             ConfigurationWriteEnable = 0x10,
574             OperationControls = 0x14,
575             SideloadClear = 0x18,
576             ReseedIntervalWriteEnable = 0x1c,
577             ReseedInterval = 0x20,
578             SoftwareBindingWriteEnable = 0x24,
579             SealingSoftwareBinding0 = 0x28,
580             SealingSoftwareBinding1 = 0x2c,
581             SealingSoftwareBinding2 = 0x30,
582             SealingSoftwareBinding3 = 0x34,
583             SealingSoftwareBinding4 = 0x38,
584             SealingSoftwareBinding5 = 0x3c,
585             SealingSoftwareBinding6 = 0x40,
586             SealingSoftwareBinding7 = 0x44,
587             AttestationSoftwareBinding0 = 0x48,
588             AttestationSoftwareBinding1 = 0x4c,
589             AttestationSoftwareBinding2 = 0x50,
590             AttestationSoftwareBinding3 = 0x54,
591             AttestationSoftwareBinding4 = 0x58,
592             AttestationSoftwareBinding5 = 0x5c,
593             AttestationSoftwareBinding6 = 0x60,
594             AttestationSoftwareBinding7 = 0x64,
595             Salt0 = 0x68,
596             Salt1 = 0x6c,
597             Salt2 = 0x70,
598             Salt3 = 0x74,
599             Salt4 = 0x78,
600             Salt5 = 0x7c,
601             Salt6 = 0x80,
602             Salt7 = 0x84,
603             KeyVersion = 0x88,
604             MaxCreatorKeyVersionWriteEnable = 0x8c,
605             MaxCreatorKeyVersion = 0x90,
606             MaxOwnerIntermediateKeyVersionWriteEnable = 0x94,
607             MaxOwnerIntermediateKeyVersion = 0x98,
608             MaxOwnerKeyVersionWriteEnable = 0x9c,
609             MaxOwnerKeyVersion = 0xa0,
610             SoftwareShare0Output0 = 0xa4,
611             SoftwareShare0Output1 = 0xa8,
612             SoftwareShare0Output2 = 0xac,
613             SoftwareShare0Output3 = 0xb0,
614             SoftwareShare0Output4 = 0xb4,
615             SoftwareShare0Output5 = 0xb8,
616             SoftwareShare0Output6 = 0xbc,
617             SoftwareShare0Output7 = 0xc0,
618             SoftwareShare1Output0 = 0xc4,
619             SoftwareShare1Output1 = 0xc8,
620             SoftwareShare1Output2 = 0xcc,
621             SoftwareShare1Output3 = 0xd0,
622             SoftwareShare1Output4 = 0xd4,
623             SoftwareShare1Output5 = 0xd8,
624             SoftwareShare1Output6 = 0xdc,
625             SoftwareShare1Output7 = 0xe0,
626             WorkingState = 0xe4,
627             Status = 0xe8,
628             ErrorCode = 0xec,
629             FaultStatus = 0xf0,
630         }
631 
632         private enum CDISetting
633         {
634             Sealing = 0,
635             Attestation = 1,
636         }
637 
638         private enum Destination
639         {
640             None = 0,
641             AES = 1,
642             KMAC = 2,
643             OTBN = 3,
644         }
645 
646         private enum SideloadClear
647         {
648             None = 0,
649             AES = 1,
650             KMAC = 2,
651             OTBN = 3,
652         }
653 
654         private enum Status
655         {
656             Idle = 0,
657             WIP = 1,
658             DoneSuccess = 2,
659             DoneError = 3,
660         }
661     }
662 }
663