/// <summary> /// Creates a certificate using the vendor/root key containing the challengeCommonName as the /// subject. Proof-of-possession of the vendor/root key is required to enroll a root certificate /// with the Azure Device Provisioning Service. /// </summary> /// <param name="">The challenge common name "nonce"</param> /// <returns>The signed challengeCommonName</returns> public static string CreateDevIDPoP(DeviceAuthBundle bundle, string challengeCommonName) { rDeviceCertSubject = new X509Name(challengeCommonName); var rootKey = new AsymmetricCipherKeyPair(bundle.RootCredential.PubKey, bundle.RootCredential.PrivKey); var rootSigningSeed = Hash(Hash(rR00t)); var challengePoPCert = CreateDeviceCert(rootKey, bundle.DeviceIDCredential.PubKey, rootSigningSeed); var challengePoPCertPEM = DerToPem("CERTIFICATE", challengePoPCert); return(challengePoPCertPEM); }
/// <summary> /// Create keys and certificates /// </summary> /// <param name="uds">Per-device Unique Device Secret</param> /// <param name="fwid">Hash of firmware</param> /// <returns>The keys and certificates for the device</returns> public static DeviceAuthBundle CreateDeviceAuthBundle(byte[] uds, byte[] fwid) { if ((uds.Length != 32) || (fwid.Length != 32)) { throw new ArgumentException("UDS and FWID must be 32-bytes in length"); } DeviceAuthBundle authBundle = new DeviceAuthBundle(); // In a real (non-emulated) DICE system, the CDI (compound device identity) would be // created by the SoC at startup, or calculated by ROM-based code very early in boot. // Here we simulate CDI creation based on a seed (the UDS, or Unique Device Secret) // provided by the caller. byte[] cdi = DICE.GetCDI(uds, rDigest); // Real DICE/RIoT Systems create keys and certificates on boot based on seeds. The seeds // can change on various sorts of software update, but otherwise the keys and certificates // remain the same. rootSeed = Hash(rR00t); devIdSeed = Hash(cdi); aliasSeed = Hash(devIdSeed, fwid); // Vendor CA root key var rootKey = DeriveEccKey(rootSeed); // DeviceID key (should never change, but should be different for each device) var deviceID = DeriveEccKey(devIdSeed); // Device GUID (should never change, but should be different for each device) var deviceGuid = DeriveGuid(devIdSeed); // Alias key (will change on firmware update - i.e. when FWID changes) var aliasKey = DeriveEccKey(aliasSeed); // If the device or alias cert subjects contain the string "guid" replace with the per-device // GUID just calculated if (rAliasCertSubject.ToString().Contains("guid")) { rAliasCertSubject = new X509Name(rAliasCertSubject.ToString().Replace("guid", deviceGuid.ToString())); } if (rDeviceCertSubject.ToString().Contains("guid")) { rDeviceCertSubject = new X509Name(rDeviceCertSubject.ToString().Replace("guid", deviceGuid.ToString())); } // Create the self-signed root CA certificate X509Certificate rootCert = CreateRootCert(rootKey, rootSeed); // Create the DeviceID certificate signed by the root vendor CA X509Certificate devCert = CreateDeviceCert(rootKey, deviceID.Public, rootSeed); // Create the self-signed DeviceID certificate X509Certificate devCertSelfSigned = CreateSelfSignedDeviceCert(deviceID, devIdSeed); // Create the Alias Key certificate signed by the deviceID key X509Certificate aliasCert = CreateAliasCert(deviceID, aliasKey, fwid, devIdSeed); // Create a PKCS10 Certificate Signing Request (CSR) for the deviceId var deviceIdCsr = CreateCsr(deviceID, devIdSeed); // Create return structure containing the keys and certificates just created authBundle.RootCredential = new CredentialBundle { PubKey = rootKey.Public, PubKeyPem = DerToPem("PUBLIC KEY", rootKey.Public), PrivKey = rootKey.Private, Cert = rootCert, CertPem = DerToPem("CERTIFICATE", rootCert) }; authBundle.DeviceIDCredential = new CredentialBundle { PubKey = deviceID.Public, PubKeyPem = DerToPem("PUBLIC KEY", deviceID.Public), Cert = devCert, CertPem = DerToPem("CERTIFICATE", devCert) }; authBundle.SelfSignedDeviceIDCredential = new CredentialBundle { PubKey = deviceID.Public, PubKeyPem = DerToPem("PUBLIC KEY", deviceID.Public), Cert = devCertSelfSigned, CertPem = DerToPem("CERTIFICATE", devCertSelfSigned) }; authBundle.AliasCredential = new CredentialBundle { PubKey = aliasKey.Public, PubKeyPem = DerToPem("PUBLIC KEY", aliasKey.Public), PrivKey = aliasKey.Private, PrivKeyPem = DerToPem("PRIVATE KEY", aliasKey.Private), Cert = aliasCert, CertPem = DerToPem("CERTIFICATE", aliasCert) }; authBundle.Csr = new CsrBundle { Csr = deviceIdCsr, CsrPem = DerToPem("NEW CERTIFICATE REQUEST", deviceIdCsr) }; return(authBundle); }