GetEccAlg(TpmPublic pub) { if (pub.unique.GetUnionSelector() != TpmAlgId.Ecc) { return(null); } var eccParms = (EccParms)pub.parameters; bool signing = pub.objectAttributes.HasFlag(ObjectAttr.Sign); bool encrypting = pub.objectAttributes.HasFlag(ObjectAttr.Decrypt); if (!(signing ^ encrypting)) { Globs.Throw <ArgumentException>("ECC Key must either sign or decrypt"); return(null); } var scheme = eccParms.scheme.GetUnionSelector(); if (signing && scheme != TpmAlgId.Ecdsa && scheme != TpmAlgId.Null) { Globs.Throw <ArgumentException>("Unsupported ECC signing scheme"); return(null); } if (!IsCurveSupported(eccParms.curveID)) { Globs.Throw <ArgumentException>("Unsupported ECC curve"); return(null); } int curveIndex = (int)eccParms.curveID; return(signing ? EcdsaCurveIDs[curveIndex] : EcdhCurveIDs[curveIndex]); }
public TpmPolicyTicket(TpmPublic authorizingKey, byte[] policyRef, TpmSt ticketType) : base("") { AuthorizingKey = authorizingKey; PolicyRef = Globs.CopyData(policyRef); TicketType = ticketType; }
/// <summary> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key - SymDefObject symDef = GetSymDef(keyParameters); byte[] symmKey; if (symDef.Algorithm != TpmAlgId.Null) { using (var symmCipher = SymmCipher.Create(symDef)) { symmKey = symmCipher.KeyData; } } else { symmKey = new byte[0]; } // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return(newKey); }
/// <summary> /// This command allows policies to change. If a policy were static, /// then it would be difficult to add users to a policy. This command lets a /// policy authority sign a new policy so that it may be used in an existing policy. /// </summary> public TpmPolicyAuthorize( byte[] policyToReplace, byte[] policyRef, TpmPublic signingKey, TpmAlgId signingHash, ISignatureUnion signature, string branchName = "") : base(branchName) { PolicyToReplace = Globs.CopyData(policyToReplace); PolicyRef = Globs.CopyData(policyRef); SigningKey = signingKey; SigningHash = signingHash; // todo - this should really be an ISigntatureUnion but the stock serializer // can't serialize interfaces //Signature = (SignatureRsassa)signature; // ReSharper disable once CanBeReplacedWithTryCastAndCheckForNull if (signature is SignatureRsapss) { Sig1 = (SignatureRsapss)signature; } // ReSharper disable once CanBeReplacedWithTryCastAndCheckForNull if (signature is SignatureRsassa) { Sig2 = (SignatureRsassa)signature; } }
public TpmPolicySigned(AsymCryptoSystem authorityKey, bool useNonceTpm, int expirationTime, byte[] cpHash, byte[] policyRef = null, string branchName = "", string nodeId = null) : base(useNonceTpm, expirationTime, cpHash, policyRef, branchName, nodeId) { SwSigningKey = authorityKey; SigningKeyPub = SwSigningKey.GetPublicParms(); AuthObjectName = authorityKey.GetPublicParms().GetName(); }
/// <summary> /// Instantiates the object using a TPM generated key pair /// </summary> /// <param name="pub"></param> /// <param name="priv"></param> public RawRsa(TpmPublic pub, TpmPrivate priv) { var m = new Marshaller(priv.buffer); var privSize = m.Get <UInt16>(); // Assert that the private key blob is in plain text Debug.Assert(priv.buffer.Length == privSize + 2); var sens = m.Get <Sensitive>(); Init(pub, sens.sensitive as Tpm2bPrivateKeyRsa); }
/// <summary> /// This is called from TpmPolicySigned when an external caller must sign the session data. /// </summary> /// <returns></returns> internal ISignatureUnion ExecuteSignerCallback(TpmPolicySigned ace, byte[] nonceTpm, out TpmPublic verificationKey) { if (SignerCallback == null) { Globs.Throw("No policy signer callback installed."); verificationKey = new TpmPublic(); return(null); } return(SignerCallback(this, ace, nonceTpm, out verificationKey)); }
public async Task <Tpm2CreateResponse> CreateAsync( TpmHandle parentHandle, SensitiveCreate inSensitive, TpmPublic inPublic, byte[] outsideInfo, PcrSelection[] creationPCR) { var inS = new Tpm2CreateRequest(parentHandle, inSensitive, inPublic, outsideInfo, creationPCR); var resp = new Tpm2CreateResponse(); await Task.Run(() => DispatchMethod(TpmCc.Create, inS, resp, 1, 0)); return(resp); }
TkVerified SignApproval(Tpm2 tpm, byte[] approvedPolicy, byte[] policyRef, TpmHandle hSigKey, ISigSchemeUnion scheme = null) { byte[] name, qname; TpmPublic pub = tpm.ReadPublic(hSigKey, out name, out qname); byte[] dataToSign = Globs.Concatenate(approvedPolicy, policyRef); byte[] aHash = CryptoLib.HashData(pub.nameAlg, dataToSign); // Create an authorization certificate for the "approvedPolicy" var sig = tpm.Sign(hSigKey, aHash, scheme, new TkHashcheck()); return(tpm.VerifySignature(hSigKey, aHash, sig)); }
public async Task <Tpm2CreateResponse> CreateAsync( TpmHandle parentHandle, SensitiveCreate inSensitive, TpmPublic inPublic, byte[] outsideInfo, PcrSelection[] creationPCR) { var inS = new Tpm2CreateRequest(parentHandle, inSensitive, inPublic, outsideInfo, creationPCR); TpmStructureBase outSBase = null; await Task.Run(() => DispatchMethod(TpmCc.Create, inS, typeof(Tpm2CreateResponse), out outSBase, 1, 0)); var outS = (Tpm2CreateResponse)outSBase; return(outS); }
/// <summary> /// Creates a *software* key. The key will be random (not created from /// a seed). The key can be used as the root of a software hierarchy that /// can be translated into a duplication blob ready for import into a TPM. /// Depending on the type of key, the software root key can be a parent for /// other root keys that can comprise a migration group. The caller should /// specify necessary key parameters in Public. /// /// Parameter keyData is used only with symmetric or HMAC keys. If non-null /// on entry, it contains the key bytes supplied by the caller, otherwise the /// key will be randomly generated. For asymmetric keys keyData must be null. /// /// Parameter authVal specifies the authorization value associated with the key. /// If it is null, then an random value will be used. /// </summary> /// <param name="pub"></param> /// <param name="authVal"></param> /// <param name="keyData"></param> /// <returns></returns> public static TssObject Create(TpmPublic pub, AuthValue authVal = null, byte[] keyData = null) { var newKey = new TssObject(); // Create a new key from the supplied parameters IPublicIdUnion publicId; var sensData = CreateSensitiveComposite(pub, ref keyData, out publicId); var nameSize = CryptoLib.DigestSize(pub.nameAlg); // Create the associated seed value byte[] seed = Globs.GetRandomBytes(nameSize); // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal ?? AuthValue.FromRandom(nameSize), seed, sensData); newKey.Sensitive = sens; newKey.Private = new TpmPrivate(sens.GetTpm2BRepresentation()); // fill in the public data newKey.Public = pub.Copy(); if (pub.type == TpmAlgId.Keyedhash || pub.type == TpmAlgId.Symcipher) { byte[] unique = null; if (pub.objectAttributes.HasFlag(ObjectAttr.Restricted | ObjectAttr.Decrypt)) { unique = CryptoLib.Hmac(pub.nameAlg, seed, keyData); } else { unique = CryptoLib.HashData(pub.nameAlg, seed, keyData); } newKey.Public.unique = pub.type == TpmAlgId.Keyedhash ? new Tpm2bDigestKeyedhash(unique) as IPublicIdUnion : new Tpm2bDigestSymcipher(unique); } else { newKey.Public.unique = publicId; } // And return the new key return(newKey); }
/// <summary> /// Create a non-migratable RSA primary with the specified use-auth value and key size. /// </summary> /// <param name="parentAuth"></param> /// <param name="keyLen"></param> /// <param name="restricted"></param> /// <param name="useAuth"></param> /// <param name="parentHandle"></param> /// <param name="policy"></param> /// <returns></returns> public async Task <Tpm2CreateResponse> CreateRsaSigningAsync( TpmHandle parentHandle, AuthValue parentAuth, int keyLen, bool restricted, AuthValue useAuth, TpmHash policy = null) { ObjectAttr attr = ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-duplicatable ObjectAttr.SensitiveDataOrigin | ObjectAttr.UserWithAuth; // Authorize with auth-data if (restricted) { attr |= ObjectAttr.Restricted; } var thePolicy = new byte[0]; if ((Object)policy != null) { thePolicy = policy; attr |= ObjectAttr.AdminWithPolicy; } var signKeyPubTemplate = new TpmPublic(H.NameHash, attr, thePolicy, new RsaParms(new SymDefObject(), // Key type and sig scheme H.RsaSigScheme, (ushort)keyLen, 0), new Tpm2bPublicKeyRsa()); // Auth-data for new key var sensCreate = new SensitiveCreate(useAuth, new byte[0]); // Create the key var newKey = await H.Tpm[parentAuth].CreateAsync(parentHandle, sensCreate, signKeyPubTemplate, new byte[0], new PcrSelection[0]); return(newKey); }
internal async Task <Tpm2CreatePrimaryResponse> CreatePrimaryRsaAsyncInternal( int keyLen, byte[] useAuth, byte[] policyAuth, PcrSelection[] pcrSel) { ObjectAttr attr = ObjectAttr.Restricted | ObjectAttr.Decrypt | ObjectAttr.FixedParent | ObjectAttr.FixedTPM | ObjectAttr.SensitiveDataOrigin; var theUseAuth = new byte[0]; if (useAuth != null) { theUseAuth = useAuth; attr |= ObjectAttr.UserWithAuth; } var thePolicyAuth = new byte[0]; if (policyAuth != null) { thePolicyAuth = policyAuth; attr |= ObjectAttr.AdminWithPolicy; } var theSelection = new PcrSelection[0]; if (pcrSel != null) { theSelection = pcrSel; } var sensCreate = new SensitiveCreate(theUseAuth, new byte[0]); var parms = new TpmPublic(H.NameHash, attr, thePolicyAuth, new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), new NullAsymScheme(), (ushort)keyLen, 0), new Tpm2bPublicKeyRsa()); byte[] outsideInfo = Globs.GetRandomBytes(8); return(await H.Tpm.CreatePrimaryAsync(TpmRh.Owner, sensCreate, parms, outsideInfo, theSelection)); }
/// <summary> /// Create a new asymmetric key based on the parameters in keyParms. The resulting key data is returned in structures /// suitable for incorporation in a TPMT_PUBLIC and TPMS_SENSITIVE /// </summary> /// <param name="keyParms"></param> /// <param name="publicParms"></param> /// <returns></returns> internal static ISensitiveCompositeUnion CreateSensitiveComposite(TpmPublic keyParms, out IPublicIdUnion publicParms) { TpmAlgId keyAlgId = keyParms.type; ISensitiveCompositeUnion newSens; // Create the asymmetric key if (keyAlgId != TpmAlgId.Rsa) { Globs.Throw <ArgumentException>("Algorithm not supported"); } var newKeyPair = new RawRsa((keyParms.parameters as RsaParms).keyBits); // Put the key bits into the required structure envelopes newSens = new Tpm2bPrivateKeyRsa(newKeyPair.Private); publicParms = new Tpm2bPublicKeyRsa(newKeyPair.Public); return(newSens); }
/// <summary> /// Extract and return the SymDefObject that describes the associated symmetric algorithm that is used for key protection /// in storage keys. /// </summary> /// <param name="keyParms"></param> /// <returns></returns> internal static SymDefObject GetSymDef(TpmPublic keyParms) { TpmAlgId keyAlgId = keyParms.type; switch (keyAlgId) { case TpmAlgId.Rsa: var rsaParms = (RsaParms)keyParms.parameters; return(rsaParms.symmetric); case TpmAlgId.Ecc: var eccParms = (EccParms)keyParms.parameters; return(eccParms.symmetric); default: throw new Exception("Unsupported algorithm"); } }
/// <summary> /// Create a new random software key (public and private) matching the parameters in keyParams. /// </summary> /// <param name="keyParams"></param> /// <returns></returns> public AsymCryptoSystem(TpmPublic keyParams) { TpmAlgId keyAlgId = keyParams.type; PublicParms = keyParams.Copy(); switch (keyAlgId) { case TpmAlgId.Rsa: { var rsaParams = keyParams.parameters as RsaParms; AsymmetricKeyAlgorithmProvider RsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha256); Key = RsaProvider.CreateKeyPair(rsaParams.keyBits); IBuffer keyBlobBuffer = Key.ExportPublicKey(CryptographicPublicKeyBlobType.BCryptPublicKey); byte[] blob; CryptographicBuffer.CopyToByteArray(keyBlobBuffer, out blob); var m = new Marshaller(blob, DataRepresentation.LittleEndian); var header = m.Get <BCryptRsaKeyBlob>(); var modulus = m.GetArray <byte>((int)header.cbModulus); var pubId = new Tpm2bPublicKeyRsa(modulus); PublicParms.unique = pubId; break; } case TpmAlgId.Ecc: { var eccParms = keyParams.parameters as EccParms; var alg = RawEccKey.GetEccAlg(keyParams); if (alg == null) { Globs.Throw <ArgumentException>("Unknown ECC curve"); return; } AsymmetricKeyAlgorithmProvider EccProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(alg); Key = EccProvider.CreateKeyPair((uint)RawEccKey.GetKeyLength(eccParms.curveID)); break; } default: Globs.Throw <ArgumentException>("Algorithm not supported"); break; } }
void Init(TpmPublic pub, Tpm2bPrivateKeyRsa priv) { var parms = pub.parameters as RsaParms; NumBits = parms.keyBits; E = new BigInteger(parms.exponent == 0 ? RsaParms.DefaultExponent : BitConverter.GetBytes(parms.exponent)); N = FromBigEndian((pub.unique as Tpm2bPublicKeyRsa).buffer); P = FromBigEndian(priv.buffer); Q = N / P; Debug.Assert(N % P == BigInteger.Zero); BigInteger PHI = N - (P + Q - BigInteger.One); D = ModInverse(E, PHI); InverseQ = ModInverse(Q, P); DP = D % (P - BigInteger.One); DQ = D % (Q - BigInteger.One); }
/// <summary> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key byte[] symmKey = Globs.GetRandomBytes(CryptoLib.DigestSize(keyParameters.nameAlg)); // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return(newKey); }
public async Task <Tpm2CreatePrimaryResponse> CreatePrimaryAsync( TpmHandle primaryHandle, SensitiveCreate inSensitive, TpmPublic inPublic, byte[] outsideInfo, PcrSelection[] creationPCR) { var inS = new Tpm2CreatePrimaryRequest { primaryHandle = primaryHandle, inSensitive = inSensitive, inPublic = inPublic, outsideInfo = outsideInfo, creationPCR = creationPCR }; TpmStructureBase outSBase = null; await Task.Run(() => DispatchMethod(TpmCc.CreatePrimary, inS, typeof(Tpm2CreatePrimaryResponse), out outSBase, 1, 1)); var outS = (Tpm2CreatePrimaryResponse)outSBase; return(outS); }
} // class PrivateKeyBlob // Trailing parameters are used to populate TpmPublic generated for the key from the blob. public static TpmPrivate CspToTpm(byte[] cspPrivateBlob, out TpmPublic tpmPub, TpmAlgId nameAlg = TpmAlgId.Sha1, ObjectAttr keyAttrs = ObjectAttr.Decrypt | ObjectAttr.UserWithAuth, IAsymSchemeUnion scheme = null, SymDefObject symDef = null) { if (scheme == null) { scheme = new NullAsymScheme(); } if (symDef == null) { symDef = new SymDefObject(); } var m = new Marshaller(cspPrivateBlob, DataRepresentation.LittleEndian); var cspPrivate = m.Get <Csp.PrivateKeyBlob>(); var keyAlg = cspPrivate.publicKeyStruc.aiKeyAlg; if (keyAlg != Csp.AlgId.CAlgRsaKeyX && keyAlg != Csp.AlgId.CAlgRsaSign) { Globs.Throw <NotSupportedException>("CSP blobs for keys of type " + keyAlg.ToString("X") + " are not supported"); tpmPub = new TpmPublic(); return(new TpmPrivate()); } var rsaPriv = new Tpm2bPrivateKeyRsa(Globs.ReverseByteOrder(cspPrivate.prime1)); var sens = new Sensitive(new byte[0], new byte[0], rsaPriv); tpmPub = new TpmPublic(nameAlg, keyAttrs, new byte[0], new RsaParms(symDef, scheme, (ushort)cspPrivate.rsaPubKey.bitlen, cspPrivate.rsaPubKey.pubexp), new Tpm2bPublicKeyRsa(Globs.ReverseByteOrder(cspPrivate.modulus))); return(new TpmPrivate(sens.GetTpm2BRepresentation())); }
/// <summary> /// Extract and return the SymDefObject that describes the associated symmetric /// algorithm that is used for key protection in storage keys. /// </summary> /// <param name="keyParms"></param> /// <returns></returns> internal static SymDefObject GetSymDef(TpmPublic keyParms) { TpmAlgId keyAlgId = keyParms.type; switch (keyAlgId) { case TpmAlgId.Rsa: var rsaParms = (RsaParms)keyParms.parameters; return(rsaParms.symmetric); case TpmAlgId.Ecc: var eccParms = (EccParms)keyParms.parameters; return(eccParms.symmetric); case TpmAlgId.Symcipher: return(keyParms.parameters is SymcipherParms ? (keyParms.parameters as SymcipherParms).sym : keyParms.parameters as SymDefObject); default: Globs.Throw("Unsupported key type"); return(new SymDefObject()); } }
///<param name = "the_publicPart">Public part of key</param> ///<param name = "the_sensitivePart">Sensitive part of key</param> ///<param name = "the_privatePart">Private part is the encrypted sensitive part of key</param> public TssObject( TpmPublic the_publicPart, Sensitive the_sensitivePart, TpmPrivate the_privatePart ) { this.publicPart = the_publicPart; this.sensitivePart = the_sensitivePart; this.privatePart = the_privatePart; }
public TssObject() { publicPart = new TpmPublic(); sensitivePart = new Sensitive(); privatePart = new TpmPrivate(); }
/// <summary> /// Create a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <param name="privKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(Native.BCRYPT_RSA_ALGORITHM); cs.Key = alg.LoadRSAKey(exponent, modulus, prime1, prime2); alg.Close(); #else var dotNetPubParms = new RSAParameters() { Exponent = exponent, Modulus = modulus }; if (privKey != null) { dotNetPubParms.P = prime1; dotNetPubParms.Q = prime2; dotNetPubParms.D = RawRsa.ToBigEndian(rr.D); dotNetPubParms.InverseQ = RawRsa.ToBigEndian(rr.InverseQ); dotNetPubParms.DP = RawRsa.ToBigEndian(rr.DP); dotNetPubParms.DQ = RawRsa.ToBigEndian(rr.DQ); } cs.RsaProvider = new RSACryptoServiceProvider(); cs.RsaProvider.ImportParameters(dotNetPubParms); #endif break; } #if !__MonoCS__ case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); #if TSS_USE_BCRYPT var alg = new BCryptAlgorithm(algId); cs.Key = alg.ImportKeyPair(Native.BCRYPT_ECCPUBLIC_BLOB, keyBlob); alg.Close(); if (cs.Key == UIntPtr.Zero) { Globs.Throw("Failed to create new RSA key"); return(null); } #else CngKey eccKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob); if (pubKey.objectAttributes.HasFlag(ObjectAttr.Sign)) { cs.EcdsaProvider = new ECDsaCng(eccKey); } else { cs.EcDhProvider = new ECDiffieHellmanCng(eccKey); } #endif // !TSS_USE_BCRYPT break; } #endif // !__MonoCS__ default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }
public TssKey(TssKey the_TssKey) { if((Object) the_TssKey == null ) throw new ArgumentException(Globs.GetResourceString("parmError")); publicPart = the_TssKey.publicPart; privatePart = the_TssKey.privatePart; }
public Tpm2bPublic(Tpm2bPublic the_Tpm2bPublic) { if((Object) the_Tpm2bPublic == null ) throw new ArgumentException(Globs.GetResourceString("parmError")); publicArea = the_Tpm2bPublic.publicArea; }
public TpmHandle Load( TpmHandle parentHandle, TpmPrivate inPrivate, TpmPublic inPublic ) { Tpm2LoadRequest inS = new Tpm2LoadRequest(); inS.parentHandle = parentHandle; inS.inPrivate = inPrivate; inS.inPublic = inPublic; TpmStructureBase outSBase; DispatchMethod(TpmCc.Load, (TpmStructureBase) inS, typeof(Tpm2LoadResponse), out outSBase, 1, 1); Tpm2LoadResponse outS = (Tpm2LoadResponse) outSBase; return outS.objectHandle; }
/// <summary> /// Some policies can be evaluated solely from public parts of the policy. /// Others need a private keyholder to sign some data. Tpm2Lib provides a /// callback facility for these cases. In this sample the callback /// signs some data using a software key. But the callback might also /// ask for a smartcard to sign a challenge, etc. /// </summary> /// <param name="tpm">reference to the TPM2 object to use.</param> static void PolicyEvaluationWithCallback(Tpm2 tpm) { Console.WriteLine("Policy evaluation with callback sample."); // // Check if policy commands are implemented by TPM. This list // could include all the other used commands as well. // This check here makes sense for policy commands, because // usually a policy has to be executed in full. If a command // out of the chain of policy commands is not implemented in the // TPM, the policy cannot be satisfied. // var usedCommands = new[] { TpmCc.PolicySigned, TpmCc.PolicyGetDigest }; foreach (var commandCode in usedCommands) { if (!tpm.Helpers.IsImplemented(commandCode)) { Console.WriteLine("Cancel Policy evaluation callback sample, because command {0} is not implemented by TPM.", commandCode); return; } } // // Template for a software signing key // var signKeyPublicTemplate = new TpmPublic(TpmAlgId.Sha256, ObjectAttr.Sign | ObjectAttr.Restricted, new byte[0], new RsaParms(SymDefObject.NullObject(), new SchemeRsassa(TpmAlgId.Sha1), 2048, 0), new Tpm2bPublicKeyRsa()); // // Create a new random key // _publicSigningKey = new AsymCryptoSystem(signKeyPublicTemplate); // // Create a policy containing a TpmPolicySigned referring to the new // software signing key. // _expectedExpirationTime = 60; var policy = new PolicyTree(TpmAlgId.Sha256); policy.Create( new PolicyAce[] { new TpmPolicySigned(_publicSigningKey.GetPublicParms().GetName(), // Newly created PubKey true, // nonceTpm required, expiration time is given _expectedExpirationTime, // expirationTime for policy new byte[0], // cpHash new byte[] {1, 2, 3, 4}) // policyRef {NodeId = "Signing Key 1"}, // Distinguishing name new TpmPolicyChainId("leaf") // Signed data }); // // Compute the expected hash for the policy session. This hash would be // used in the object associated with the policy to confirm that the // policy is actually fulfilled. // TpmHash expectedHash = policy.GetPolicyDigest(); // // The use of the object associated with the policy has to evaluate the // policy. In order to process TpmPolicySigned the caller will have to // sign a data structure challenge from the TPM. Here we install a // callback that will sign the challenge from the TPM. // policy.SetSignerCallback(SignerCallback); // // Evaluate the policy. Tpm2Lib will traverse the policy tree from leaf to // root (in this case just TpmPolicySigned) and will call the signer callback // to get a properly-formed challenge signed. // AuthSession authSession = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); authSession.RunPolicy(tpm, policy, "leaf"); // // And check that the TPM policy hash is what we expect // byte[] actualHash = tpm.PolicyGetDigest(authSession.Handle); if (expectedHash != actualHash) { throw new Exception("Policy evaluation error"); } Console.WriteLine("TpmPolicySignature evaluated."); // // Clean up // tpm.FlushContext(authSession.Handle); }
public TssObject(TpmPublic thePublicPart, TpmPrivate thePrivatePart) { Public = thePublicPart; Private = thePrivatePart; }
public TpmPublic(TpmPublic the_TpmPublic) { if((Object) the_TpmPublic == null ) throw new ArgumentException(Globs.GetResourceString("parmError")); nameAlg = the_TpmPublic.nameAlg; objectAttributes = the_TpmPublic.objectAttributes; authPolicy = the_TpmPublic.authPolicy; }
/// <summary> /// The callback to sign the TpmPolicySignature challenge from the TPM. /// </summary> /// <param name="policyTree">The policy tree to check.</param> /// <param name="ace">The policy element (TpmPolicySignature) to evaluate.</param> /// <param name="nonceTpm">The nonce from the TPM.</param> /// <returns>Signature of the nonce.</returns> public static ISignatureUnion SignerCallback(PolicyTree policyTree, TpmPolicySigned ace, byte[] nonceTpm, out TpmPublic verificationKey) { // // This function checks the parameters of the associated TpmPolicySigned // ACE, and if they are those expected the TPM challenge is signed. // Note that policy expressions are often obtained from untrustworthy // sources, so it is important for key-holders to check what they // are bing asked to do before signing anything. // // // The policy just contains the name of the signature verification key, however the // TPM needs the actual public key to verify the signature. Check that the name // matches, and if it does return the public key. // byte[] expectedName = _publicSigningKey.GetPublicParms().GetName(); if (!expectedName.SequenceEqual(ace.AuthObjectName)) { throw new Exception("Unexpected name in policy."); } verificationKey = _publicSigningKey.GetPublicParms(); // // Check that the key is the one that we expect // if (ace.NodeId != "Signing Key 1") { throw new Exception("Unrecognized key"); } // // Check that nonceTom is not null (otherwise anything we sign can // be used for any session). // if (nonceTpm.Length == 0) { throw new Exception("Sign challenges with expiration time need nonce."); } // // Check PolicyRef and cpHash are what we want to sign // if (ace.CpHash.Length != 0) { throw new Exception("I only sign null-cpHash"); } if (!ace.PolicyRef.SequenceEqual(new byte[] { 1, 2, 3, 4 })) { throw new Exception("Incorrect PolicyRef"); } // // And finally check that the expiration is set correctly. Check for // positive values (simple signing policy) and negative values (sining // policy with ticket). // if (ace.ExpirationTime != _expectedExpirationTime) { throw new Exception("Unexpected expiration time"); } // // Everything is OK, so get a formatted bloc containing the challenge // data and then sign it. // byte[] dataStructureToSign = PolicyTree.GetDataStructureToSign(ace.ExpirationTime, nonceTpm, ace.CpHash, ace.PolicyRef); ISignatureUnion signature = _publicSigningKey.Sign(dataStructureToSign); return signature; }
/// <summary> /// This is called from TpmPolicySigned when an external caller must sign the session data. /// </summary> /// <returns></returns> internal ISignatureUnion ExecuteSignerCallback(TpmPolicySigned ace, byte[] nonceTpm, out TpmPublic verificationKey) { if (SignerCallback == null) { Globs.Throw("No policy signer callback installed."); verificationKey = new TpmPublic(); return null; } ISignatureUnion signature = SignerCallback(this, ace, nonceTpm, out verificationKey); return signature; }
public async Task<Tpm2CreateResponse> CreateAsync( TpmHandle parentHandle, SensitiveCreate inSensitive, TpmPublic inPublic, byte[] outsideInfo, PcrSelection[] creationPCR) { var inS = new Tpm2CreateRequest { parentHandle = parentHandle, inSensitive = inSensitive, inPublic = inPublic, outsideInfo = outsideInfo, creationPCR = creationPCR }; TpmStructureBase outSBase = null; await Task.Run(() => DispatchMethod(TpmCc.Create, inS, typeof (Tpm2CreateResponse), out outSBase, 1, 0)); var outS = (Tpm2CreateResponse)outSBase; return outS; }
///<param name = "the_publicArea">the public area NOTE The + indicates that the caller may specify that use of TPM_ALG_NULL is allowed for nameAlg.</param> public Tpm2bPublic( TpmPublic the_publicArea ) { this.publicArea = the_publicArea; }
///<param name = "the_objectHandle">handle of type TPM_HT_TRANSIENT for created Primary Object</param> ///<param name = "the_outPublic">the public portion of the created object</param> ///<param name = "the_creationData">contains a TPMT_CREATION_DATA</param> ///<param name = "the_creationHash">digest of creationData using nameAlg of outPublic</param> ///<param name = "the_creationTicket">ticket used by TPM2_CertifyCreation() to validate that the creation data was produced by the TPM</param> ///<param name = "the_name">the name of the created object</param> public Tpm2CreatePrimaryResponse( TpmHandle the_objectHandle, TpmPublic the_outPublic, CreationData the_creationData, byte[] the_creationHash, TkCreation the_creationTicket, byte[] the_name ) { this.objectHandle = the_objectHandle; this.outPublic = the_outPublic; this.creationData = the_creationData; this.creationHash = the_creationHash; this.creationTicket = the_creationTicket; this.name = the_name; }
/// <summary> /// This sample demonstrates a policy containing ALL policy commands. /// It also demonstrates serialization of the policy, and the use /// of callbacks to satisfy the conditions in a policy (e.g. knowledge /// of a private key, or the NV-index associated with a name. /// </summary> /// <param name="tpm">Reference to the TPM used.</param> static void SamplePolicySerializationAndCallbacks(Tpm2 tpm) { Console.WriteLine("Policy sample that serializes all policy commands."); // // Check if policy commands are implemented by TPM. This list // could include all the other used commands as well. // This check here makes sense for policy commands, because // usually a policy has to be executed in full. If a command // out of the chain of policy commands is not implemented in the // TPM, the policy cannot be satisfied. // var usedCommands = new[] { TpmCc.PolicyPhysicalPresence, TpmCc.PolicySigned, TpmCc.PolicySecret, TpmCc.PolicyPCR, TpmCc.PolicyLocality, TpmCc.PolicyNV, TpmCc.PolicyCounterTimer, TpmCc.PolicyCommandCode, TpmCc.PolicyPassword, TpmCc.PolicyAuthorize, TpmCc.PolicyPhysicalPresence, TpmCc.PolicyCpHash, TpmCc.PolicyTicket, TpmCc.PolicyNameHash, TpmCc.PolicyCpHash, TpmCc.PolicyDuplicationSelect, TpmCc.PolicyAuthValue, TpmCc.PolicyNvWritten }; foreach (var commandCode in usedCommands) { if (!tpm.Helpers.IsImplemented(commandCode)) { Console.WriteLine("Cancel Policy serialization and callback sample, because command {0} is not implemented by TPM.", commandCode); return; } } // // AuthValue encapsulates an authorization value: essentially a byte-array. // OwnerAuth is the owner authorization value of the TPM-under-test. We // assume that it (and other) auths are set to the default (null) value. // If running on a real TPM, which has been provisioned by Windows, this // value will be different. An administrator can retrieve the owner // authorization value from the registry. // var ownerAuth = new AuthValue(); var pInit = new PolicyTree(TpmAlgId.Sha256); var p = new PolicyTree(TpmAlgId.Sha256); // // In the first part of this sample we establish keys, NV-slots, // etc. that will be used in the policy. // // // create a new RSA software signing key. We will use this for both // TpmPolicySigned AND TpmPolicyAuthorize. // var signKeyPublicTemplate = new TpmPublic(TpmAlgId.Sha256, ObjectAttr.Sign | ObjectAttr.Restricted | ObjectAttr.FixedTPM, new byte[0], new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa()); _publicSigningKey = new AsymCryptoSystem(signKeyPublicTemplate); // // Get an authorization ticket for TpmPolicyAuthorize. We will authorize // a policy-digest consisting of policyPhysPresense. // var tempPolicy = new PolicyTree(TpmAlgId.Sha256); tempPolicy.Create( new PolicyAce[] { new TpmPolicyPhysicalPresence(), "leaf" }); TpmHash initPolicyHash = tempPolicy.GetPolicyDigest(); var policyAuthRef = new byte[0]; byte[] dataToSign = Globs.Concatenate(initPolicyHash.HashData, policyAuthRef); byte[] aHash = CryptoLib.HashData(TpmAlgId.Sha256, Globs.Concatenate(initPolicyHash.HashData, policyAuthRef)); // // Sign the simple policy just containing PolicyPhysPres so that // we can change it to a new value with PolicyAuthorize. // ISignatureUnion policyAuthSig = _publicSigningKey.Sign(dataToSign); // // Get a ticket verifying the signature. // TpmHandle verifierHandle = tpm.LoadExternal(null, _publicSigningKey.GetPublicParms(), TpmHandle.RhOwner); tpm.VerifySignature(verifierHandle, aHash, policyAuthSig); tpm.FlushContext(verifierHandle); // // Get the value of PCR[1] // var pcrs = new uint[] { 1 }; var sel = new PcrSelection(TpmAlgId.Sha, pcrs); PcrSelection[] selOut; Tpm2bDigest[] pcrValues; tpm.PcrRead(new[] { sel }, out selOut, out pcrValues); // // Save the current PCR values in a convenient data structure // var expectedPcrVals = new PcrValueCollection(selOut, pcrValues); // // Set up an NV slot // TpmHandle nvHandle = TpmHandle.NV(3001); // // Clean anything that might have been there before // tpm[ownerAuth]._AllowErrors().NvUndefineSpace(TpmHandle.RhOwner, nvHandle); AuthValue nvAuth = AuthValue.FromRandom(8); tpm[ownerAuth].NvDefineSpace(TpmHandle.RhOwner, nvAuth, new NvPublic(nvHandle, TpmAlgId.Sha1, NvAttr.TpmaNvAuthread | NvAttr.TpmaNvAuthwrite, new byte[0], 32)); // // write some data // var nvData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; tpm[nvAuth].NvWrite(nvHandle, nvHandle, nvData, 0); byte[] nvName; tpm.NvReadPublic(nvHandle, out nvName); // // Install evaluation callback // Note: generally the callback will check that the parameters are // actions that it is willing to authorize. Those checks are omitted here. // p.SetNvCallback((PolicyTree policyTree, TpmPolicyNV ace, out SessionBase authorizingSession, out TpmHandle authorizedEntityHandle, out TpmHandle nvHandleIs) => { authorizedEntityHandle = nvHandle; nvHandleIs = nvHandle; authorizingSession = nvAuth; }); // // counter-timer: The policy will check that the reset-count // is the current value. // int start, end; TimeInfo now = tpm.ReadClock(); Marshaller.GetFragmentInfo(now, "resetCount", out start, out end); byte[] operandB = Marshaller.GetTpmRepresentation(now.clockInfo.resetCount); // // Get a cpHash for the command we want to execute // var cpHash = new TpmHash(TpmAlgId.Sha256); tpm._GetCpHash(cpHash).HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); p.SetSignerCallback(SignerCallback); // // PolicySecret tests knowledge of ownerAuth. Note that the callback // will generally check that it is prepared to authorize what it is // being asked to authorize. Those checks are omitted here (we just // provide a PWAP session containing ownerAuth. // p.SetPolicySecretCallback((PolicyTree policyTree, TpmPolicySecret ace, out SessionBase authorizingSession, out TpmHandle authorizedEntityHandle, out bool flushAuthEntity) => { authorizingSession = ownerAuth; authorizedEntityHandle = TpmHandle.RhOwner; flushAuthEntity = false; }); // // If the policy contains a TpmPolicyAction then print out the // action string on the console. // p.SetPolicyActionCallback((PolicyTree policy, TpmPolicyAction ace) => Console.WriteLine(ace.Action)); var policyRef = new byte[] { 1, 2, 3, 4 }; // // Ticket expiration times have to be negative. // Positive expiration times do not generate a ticket. // _expectedExpirationTime = -60; // // A normalized policy is an array of policy-chains written as // arrays. Here "most" of the policy-ACEs are in the first chain, but some // ACEs cannot co-exist, and some need a ticket from a prior evaluation. // pInit.CreateNormalizedPolicy( new[] { new PolicyAce[] { new TpmPolicySigned(_publicSigningKey.GetPublicParms().GetName(), // Newly created PubKey true, // Nonce in signed data _expectedExpirationTime, // expirationTime new byte[0], // cpHash policyRef) // policyRef {NodeId = "Signing Key 1"}, // Distinguishing name // // Include owner-auth // new TpmPolicySecret(TpmHandle.RhOwner.GetName(), true, new byte[0], new byte[] {1, 2, 3}, 0), // // Include PCR-values read earlier // new TpmPolicyPcr(expectedPcrVals), // // Command must be issued at locality two // new TpmPolicyLocality(LocalityAttr.TpmLocTwo), // // NV-data we set earlier must be present // new TpmPolicyNV(nvName, nvData, 0, Eo.Eq), // // This is a "dummy ACE" that is not executed on the TPM but // a callback will be invoked at when the policy is executed. // One use case for this is to increment a counter between two // PolicyNV counter-checks. // new TpmPolicyAction("Output of TpmPolicyAction when executed."), // // Boot-count must be what we read earlier // new TpmPolicyCounterTimer(operandB, (ushort) start, Eo.Eq), // // Only authorize HierarchyChangeAuth // new TpmPolicyCommand(TpmCc.HierarchyChangeAuth), // // Include password // new TpmPolicyPassword(), // // Authorize a change from PolicyPP (last ACE below) // new TpmPolicyAuthorize(initPolicyHash.HashData, policyAuthRef, _publicSigningKey.GetPublicParms(), TpmAlgId.Sha256, policyAuthSig), // // Demand that the command be executed with PP asserted // new TpmPolicyPhysicalPresence(), // // Name for this branch // "branch_1" }, new PolicyAce[] { // // Bind to command/parameters // new TpmPolicyCpHash(cpHash), // // Name for this branch // "branch_2" }, new PolicyAce[] { new TpmPolicyTicket(_publicSigningKey.GetPublicParms(), policyRef, TpmSt.AuthSigned) // // Distinguishing name for this node // {NodeId = "PolicyTicket"}, // // Name for this branch // "branch_3" }, // // TODO: These ACEs are not evaluated yet in this sample // new PolicyAce[] { new TpmPolicyNameHash(), new TpmPolicyCpHash(cpHash), new TpmPolicyDuplicationSelect(new byte[0], new byte[0], true), new TpmPolicyAuthValue(), // Include entity authValue in HMAC new TpmPolicyNvWritten(), "branch_4" } } ); TpmHash policyHash = pInit.GetPolicyDigest(); // // Check that we can serialize and deserialize the policy // const string fileName = @".\test1.xml"; pInit.SerializeToFile("Sample Policy",PolicySerializationFormat.Xml, fileName); p.DeserializeFromFile(PolicySerializationFormat.Xml, fileName); // // And check that the policy hash is the same // TpmHash deserializedHash = p.GetPolicyDigest(); if (policyHash != deserializedHash) { throw new Exception("Serialization error"); } // // Execute the policy on the TPM. Start with "branch_1". // AuthSession s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); s0.RunPolicy(tpm, p, "branch_1"); // // Check that the executed policy has the correct digest // byte[] actualPolicyDigest = tpm.PolicyGetDigest(s0.Handle); if (policyHash != actualPolicyDigest) { throw new Exception("Policy Evaluation error"); } // // Set a command to use the policy // tpm[ownerAuth].SetPrimaryPolicy(TpmHandle.RhOwner, policyHash.HashData, TpmAlgId.Sha256); // // And then execute the command // tpm._AssertPhysicalPresence(true); tpm._SetLocality(LocalityAttr.TpmLocTwo); tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); tpm._SetLocality(LocalityAttr.TpmLocZero); tpm._AssertPhysicalPresence(false); tpm.FlushContext(s0.Handle); // // Next, "branch_2". // s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); s0.RunPolicy(tpm, p, "branch_2"); tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); tpm.FlushContext(s0.Handle); // // Now "branch_3" - ticket. Copy parms out of the ticket/ACE returned // from TpmPolicySinged above. // var sigAce = p.GetAce<TpmPolicySigned>("Signing Key 1"); TkAuth signedTicket = p.GetTicket("Signing Key 1"); var tickAce = p.GetAce<TpmPolicyTicket>("PolicyTicket"); tickAce.CpHash = sigAce.CpHash; tickAce.PolicyRef = sigAce.PolicyRef; tickAce.ExpirationTime = sigAce.GetTimeout(); tickAce.SetTicket(signedTicket); s0 = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); s0.RunPolicy(tpm, p, "branch_3"); tpm[s0].HierarchyChangeAuth(TpmHandle.RhOwner, ownerAuth); tpm.FlushContext(s0.Handle); Console.WriteLine("Finished SamplePolicySerializationAndCallbacks."); }
/// <summary> /// Create a new AsymCryptoSystem from TPM public parameter. This can then /// be used to validate TPM signatures or encrypt data destined for a TPM. /// </summary> /// <param name="pubKey"></param> /// <returns></returns> public static AsymCryptoSystem CreateFrom(TpmPublic pubKey, TpmPrivate privKey = null) { var cs = new AsymCryptoSystem(); TpmAlgId keyAlgId = pubKey.type; cs.PublicParms = pubKey.Copy(); // Create an algorithm provider from the provided PubKey switch (keyAlgId) { case TpmAlgId.Rsa: { RawRsa rr = null; byte[] prime1 = null, prime2 = null; if (privKey != null) { rr = new RawRsa(pubKey, privKey); prime1 = RawRsa.ToBigEndian(rr.P); prime2 = RawRsa.ToBigEndian(rr.Q); } var rsaParams = (RsaParms)pubKey.parameters; var exponent = rsaParams.exponent != 0 ? Globs.HostToNet(rsaParams.exponent) : RsaParms.DefaultExponent; var modulus = (pubKey.unique as Tpm2bPublicKeyRsa).buffer; AsymmetricKeyAlgorithmProvider rsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha256); uint primeLen1 = 0, primeLen2 = 0; // Compute the size of BCRYPT_RSAKEY_BLOB int rsaKeySize = exponent.Length + modulus.Length + 24; if (prime1 != null && prime1.Length > 0) { if (prime2 == null || prime2.Length == 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The second prime is missing"); return(null); } primeLen1 = (uint)prime1.Length; primeLen2 = (uint)prime2.Length; rsaKeySize += prime1.Length + prime2.Length; } else if (prime2 != null && prime2.Length > 0) { Globs.Throw <ArgumentException>("LoadRSAKey(): The first prime is missing"); return(null); } var rsaKey = new byte[rsaKeySize]; // Initialize BCRYPT_RSAKEY_BLOB int offset = 0; WriteToBuffer(ref rsaKey, ref offset, primeLen1 == 0 ? BCRYPT_RSAPUBLIC_MAGIC : BCRYPT_RSAPRIVATE_MAGIC); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length * 8); WriteToBuffer(ref rsaKey, ref offset, (uint)exponent.Length); WriteToBuffer(ref rsaKey, ref offset, (uint)modulus.Length); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, primeLen1); WriteToBuffer(ref rsaKey, ref offset, exponent); WriteToBuffer(ref rsaKey, ref offset, modulus); if (primeLen1 != 0) { WriteToBuffer(ref rsaKey, ref offset, prime1); WriteToBuffer(ref rsaKey, ref offset, prime2); } IBuffer rsaBuffer = CryptographicBuffer.CreateFromByteArray(rsaKey); if (primeLen1 == 0) { cs.Key = rsaProvider.ImportPublicKey(rsaBuffer, CryptographicPublicKeyBlobType.BCryptPublicKey); } else { cs.Key = rsaProvider.ImportKeyPair(rsaBuffer, CryptographicPrivateKeyBlobType.BCryptPrivateKey); } break; } case TpmAlgId.Ecc: { var eccParms = (EccParms)pubKey.parameters; var eccPub = (EccPoint)pubKey.unique; var algId = RawEccKey.GetEccAlg(pubKey); if (algId == null) { return(null); } bool isEcdsa = eccParms.scheme.GetUnionSelector() == TpmAlgId.Ecdsa; byte[] keyBlob = RawEccKey.GetKeyBlob(eccPub.x, eccPub.y, keyAlgId, !isEcdsa, eccParms.curveID); AsymmetricKeyAlgorithmProvider eccProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(algId); cs.Key = eccProvider.ImportKeyPair(CryptographicBuffer.CreateFromByteArray(keyBlob)); break; } default: Globs.Throw <ArgumentException>("Algorithm not supported"); cs = null; break; } return(cs); }
public TpmHandle CreatePrimary( TpmHandle primaryHandle, SensitiveCreate inSensitive, TpmPublic inPublic, byte[] outsideInfo, PcrSelection[] creationPCR, [SuppressMessage("Microsoft.Design", "CA1021")] out TpmPublic outPublic, [SuppressMessage("Microsoft.Design", "CA1021")] out CreationData creationData, [SuppressMessage("Microsoft.Design", "CA1021")] out byte[] creationHash, [SuppressMessage("Microsoft.Design", "CA1021")] out TkCreation creationTicket ) { Tpm2CreatePrimaryRequest inS = new Tpm2CreatePrimaryRequest(); inS.primaryHandle = primaryHandle; inS.inSensitive = inSensitive; inS.inPublic = inPublic; inS.outsideInfo = outsideInfo; inS.creationPCR = creationPCR; TpmStructureBase outSBase; DispatchMethod(TpmCc.CreatePrimary, (TpmStructureBase) inS, typeof(Tpm2CreatePrimaryResponse), out outSBase, 1, 1); Tpm2CreatePrimaryResponse outS = (Tpm2CreatePrimaryResponse) outSBase; outPublic = outS.outPublic; creationData = outS.creationData; creationHash = outS.creationHash; creationTicket = outS.creationTicket; return outS.objectHandle; }
CreateSensitiveComposite(TpmPublic pub, ref byte[] keyData, out IPublicIdUnion publicId) { ISensitiveCompositeUnion newSens = null; publicId = null; if (pub.type == TpmAlgId.Rsa) { if (keyData != null) { Globs.Throw <ArgumentException>("Cannot specify key data for an RSA key"); return(null); } var newKeyPair = new RawRsa((pub.parameters as RsaParms).keyBits); // Put the key bits into the required structure envelopes newSens = new Tpm2bPrivateKeyRsa(newKeyPair.Private); publicId = new Tpm2bPublicKeyRsa(newKeyPair.Public); } else if (pub.type == TpmAlgId.Symcipher) { var symDef = (SymDefObject)pub.parameters; if (symDef.Algorithm != TpmAlgId.Aes) { Globs.Throw <ArgumentException>("Unsupported symmetric algorithm"); return(null); } int keySize = (symDef.KeyBits + 7) / 8; if (keyData == null) { keyData = Globs.GetRandomBytes(keySize); } else if (keyData.Length != keySize) { keyData = Globs.CopyData(keyData); } else { Globs.Throw <ArgumentException>("Wrong symmetric key length"); return(null); } newSens = new Tpm2bSymKey(keyData); } else if (pub.type == TpmAlgId.Keyedhash) { var scheme = (pub.parameters as KeyedhashParms).scheme; TpmAlgId hashAlg = scheme is SchemeHash ? (scheme as SchemeHash).hashAlg : scheme is SchemeXor ? (scheme as SchemeXor).hashAlg : pub.nameAlg; var digestSize = CryptoLib.DigestSize(hashAlg); if (keyData == null) { keyData = Globs.GetRandomBytes(digestSize); } else if (keyData.Length <= CryptoLib.BlockSize(hashAlg)) { keyData = Globs.CopyData(keyData); } else { Globs.Throw <ArgumentException>("HMAC key is too big"); return(null); } newSens = new Tpm2bSensitiveData(keyData); } else { Globs.Throw <ArgumentException>("Unsupported key type"); } return(newSens); }
public TpmPrivate Import( TpmHandle parentHandle, byte[] encryptionKey, TpmPublic objectPublic, TpmPrivate duplicate, byte[] inSymSeed, SymDefObject symmetricAlg ) { Tpm2ImportRequest inS = new Tpm2ImportRequest(); inS.parentHandle = parentHandle; inS.encryptionKey = encryptionKey; inS.objectPublic = objectPublic; inS.duplicate = duplicate; inS.inSymSeed = inSymSeed; inS.symmetricAlg = symmetricAlg; TpmStructureBase outSBase; DispatchMethod(TpmCc.Import, (TpmStructureBase) inS, typeof(Tpm2ImportResponse), out outSBase, 1, 0); Tpm2ImportResponse outS = (Tpm2ImportResponse) outSBase; return outS.outPrivate; }
public TpmHandle LoadExternal( Sensitive inPrivate, TpmPublic inPublic, TpmHandle hierarchy ) { Tpm2LoadExternalRequest inS = new Tpm2LoadExternalRequest(); inS.inPrivate = inPrivate; inS.inPublic = inPublic; inS.hierarchy = hierarchy; TpmStructureBase outSBase; DispatchMethod(TpmCc.LoadExternal, (TpmStructureBase) inS, typeof(Tpm2LoadExternalResponse), out outSBase, 0, 1); Tpm2LoadExternalResponse outS = (Tpm2LoadExternalResponse) outSBase; return outS.objectHandle; }
/// <summary> /// Create an RSA primary storage key in the storage hierarchy and return the key-handle /// to the caller. The key will be RSA2048 with a SHA256-name algorithm. The caller can /// provide user-auth. The caller is responsible for disposing of this key. /// </summary> /// <returns></returns> static TpmHandle CreateRsaPrimaryStorageKey(Tpm2 tpm, byte[] auth, out TpmPublic newKeyPub) { // // Creation parameters (no external data for TPM-created objects) // var sensCreate = new SensitiveCreate(auth, // Auth-data provided by the caller new byte[0]); // No external data (the TPM will create the new key). var parms = new TpmPublic(TpmAlgId.Sha256, ObjectAttr.Restricted | ObjectAttr.Decrypt | // Storage key ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-duplicable ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin, new byte[0], // No policy, and Storage key should be RSA + AES128 new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), new NullAsymScheme(), 2048, 0), new Tpm2bPublicKeyRsa()); // // The following are returned by the TPM in CreatePrimary (and Create) // they are not used in this sample. // CreationData creationData; TkCreation creationTicket; byte[] creationHash; TpmHandle primHandle = tpm[_ownerAuth].CreatePrimary(TpmHandle.RhOwner, // In storage hierarchy sensCreate, // UserAuth parms, // Creation parms set above // // The following parameters influence the creation of the // creation-ticket. They are not used in this sample // new byte[0], // Null outsideInfo new PcrSelection[0], // Do not record PCR-state out newKeyPub, // Our outs out creationData, out creationHash, out creationTicket); return primHandle; }
///<param name = "the_publicPart">Public part of key</param> ///<param name = "the_privatePart">Private part is the encrypted sensitive part of key</param> public TssKey( TpmPublic the_publicPart, byte[] the_privatePart ) { this.publicPart = the_publicPart; this.privatePart = the_privatePart; }
/// <summary> /// This sample illustrates the creation and use of an RSA signing key to /// "quote" PCR state /// </summary> /// <param name="tpm">Reference to the TPM object.</param> static void QuotePcrs(Tpm2 tpm) { // // First use a library routine to create an RSA/AES primary storage key // with null user-auth. // TpmPublic rsaPrimaryPublic; var primaryAuth = new byte[0]; TpmHandle primHandle = CreateRsaPrimaryStorageKey(tpm, primaryAuth, out rsaPrimaryPublic); // // Template for a signing key. We will make the key restricted so that we // can quote with it too. // var signKeyPubTemplate = new TpmPublic(TpmAlgId.Sha1, ObjectAttr.Sign | ObjectAttr.Restricted | // A "quoting" key ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-duplicable ObjectAttr.UserWithAuth | // Authorize with auth-data ObjectAttr.SensitiveDataOrigin, // TPM will create a new key new byte[0], new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha1), 2048, 0), new Tpm2bPublicKeyRsa()); // // Auth-data for new key // var userAuth = new byte[] { 1, 2, 3, 4 }; var sensCreate = new SensitiveCreate(userAuth, new byte[0]); // // Creation data (not used in this sample) // CreationData childCreationData; TkCreation creationTicket; byte[] creationHash; // // Create the key // TpmPublic keyPub; TpmPrivate keyPriv = tpm[primaryAuth].Create(primHandle, // Child of primary key created above sensCreate, // Auth-data signKeyPubTemplate, // Template created above new byte[0], // Other parms are not used here new PcrSelection[0], out keyPub, out childCreationData, out creationHash, out creationTicket); Console.WriteLine("New public key\n" + keyPub.ToString()); // // Load the key as a child of the primary that it // was created under. // TpmHandle signHandle = tpm[primaryAuth].Load(primHandle, keyPriv, keyPub); // // Note that Load returns the "name" of the key and this is automatically // associated with the handle. // Console.WriteLine("Name of key:" + BitConverter.ToString(signHandle.Name)); // // Aome data to quote // TpmHash hashToSign = TpmHash.FromData(TpmAlgId.Sha1, new byte[] { 4, 3, 2, 1 }); // // PCRs to quote. SHA-1 bank, PCR-indices 1, 2, and 3 // var pcrsToQuote = new PcrSelection[] { new PcrSelection(TpmAlgId.Sha, new uint[] { 1, 2, 3 }) }; // // Ask the TPM to quote the PCR (and the nonce). The TPM // returns the quote-signature and the data that was signed // ISignatureUnion quoteSig; Attest quotedInfo = tpm[userAuth].Quote(signHandle, hashToSign.HashData, new SchemeRsassa(TpmAlgId.Sha1), pcrsToQuote, out quoteSig); // // Print out what was quoted // var info = (QuoteInfo)quotedInfo.attested; Console.WriteLine("PCRs that were quoted: " + info.pcrSelect[0].ToString() + "\nHash of PCR-array: " + BitConverter.ToString(info.pcrDigest)); // // Read the PCR to check the quoted value // PcrSelection[] outSelection; Tpm2bDigest[] outValues; tpm.PcrRead(new PcrSelection[] { new PcrSelection(TpmAlgId.Sha, new uint[] { 1, 2, 3 }) }, out outSelection, out outValues); // // Use the Tpm2Lib library to validate the quote against the // values just read. // bool quoteOk = keyPub.VerifyQuote(TpmAlgId.Sha1, outSelection, outValues, hashToSign.HashData, quotedInfo, quoteSig); if (!quoteOk) { throw new Exception("Quote did not validate"); } Console.WriteLine("Quote correctly validated."); // // Test other uses of the signing key. A restricted key can only // sign data that the TPM knows does not start with a magic // number (that identifies TPM internal data). So this does not // work // var nullProof = new TkHashcheck(TpmHandle.RhNull, new byte[0]); tpm[userAuth]._ExpectError(TpmRc.Ticket).Sign(signHandle, hashToSign.HashData, new SchemeRsassa(TpmAlgId.Sha1), nullProof); // // But if we ask the TPM to hash the same data and then sign it // then the TPM can be sure that the data is safe, so it will // sign it. // TkHashcheck safeHashTicket; TpmHandle hashHandle = tpm.HashSequenceStart(_nullAuth, TpmAlgId.Sha1); // // The ticket is only generated if the data is "safe." // tpm[_nullAuth].SequenceComplete(hashHandle, new byte[] { 4, 3, 2, 1 }, TpmHandle.RhOwner, out safeHashTicket); // // This will now work because the ticket proves to the // TPM that the data that it is about to sign does not // start with TPM_GENERATED // ISignatureUnion sig = tpm[userAuth].Sign(signHandle, hashToSign.HashData, new SchemeRsassa(TpmAlgId.Sha1), safeHashTicket); // // And we can verify the signature // bool sigOk = keyPub.VerifySignatureOverData(new byte[] { 4, 3, 2, 1 }, sig); if (!sigOk) { throw new Exception("Signature did not verify"); } Console.WriteLine("Signature verified."); // // Clean up // tpm.FlushContext(primHandle); tpm.FlushContext(signHandle); }
/// <summary> /// Create a new random software key (public and private) matching the parameters in keyParams. /// </summary> /// <param name="keyParams"></param> /// <returns></returns> public AsymCryptoSystem(TpmPublic keyParams) { TpmAlgId keyAlgId = keyParams.type; PublicParms = keyParams.Copy(); switch (keyAlgId) { case TpmAlgId.Rsa: { var rsaParams = keyParams.parameters as RsaParms; #if TSS_USE_BCRYPT Key = Generate(Native.BCRYPT_RSA_ALGORITHM, rsaParams.keyBits); if (Key == UIntPtr.Zero) { Globs.Throw("Failed to generate RSA key"); return; } byte[] blob = Export(Native.BCRYPT_RSAPUBLIC_BLOB); var m = new Marshaller(blob, DataRepresentation.LittleEndian); var header = m.Get <BCryptRsaKeyBlob>(); /*var exponent = */ m.GetArray <byte>((int)header.cbPublicExp); var modulus = m.GetArray <byte>((int)header.cbModulus); #else RsaProvider = new RSACryptoServiceProvider(rsaParams.keyBits); var modulus = RsaProvider.ExportParameters(true).Modulus; #endif var pubId = new Tpm2bPublicKeyRsa(modulus); PublicParms.unique = pubId; break; } #if !__MonoCS__ case TpmAlgId.Ecc: { var eccParms = keyParams.parameters as EccParms; var alg = RawEccKey.GetEccAlg(keyParams); if (alg == null) { Globs.Throw <ArgumentException>("Unknown ECC curve"); return; } #if TSS_USE_BCRYPT Key = Generate(alg, (uint)RawEccKey.GetKeyLength(eccParms.curveID)); #else var keyParmsX = new CngKeyCreationParameters { ExportPolicy = CngExportPolicies.AllowPlaintextExport }; using (CngKey key = CngKey.Create(alg, null, keyParmsX)) { byte[] keyIs = key.Export(CngKeyBlobFormat.EccPublicBlob); CngKey.Import(keyIs, CngKeyBlobFormat.EccPublicBlob); if (keyParams.objectAttributes.HasFlag(ObjectAttr.Sign)) { EcdsaProvider = new ECDsaCng(key); } else { EcDhProvider = new ECDiffieHellmanCng(key); } } #endif // !TSS_USE_BCRYPT && !__MonoCS__ break; } #endif // !__MonoCS__ default: Globs.Throw <ArgumentException>("Algorithm not supported"); break; } }
/// <summary> /// This sample demonstrates the creation and use of a storage root key that /// behaves like the Storage Root Key (SRK) defined in TPM1.2. /// To do this we need to create a new primary, and then use EvictControl /// to make it NV-resident. /// </summary> /// <param name="tpm">Reference to TPM object</param> static void StorageRootKey(Tpm2 tpm) { // // This template asks the TPM to create an 2048 bit RSA storage key // with an associated AES key for symmetric data protection. The term // "SRKs" is not used in TPM2.0, but we use it here to // not // var srkTemplate = new TpmPublic(TpmAlgId.Sha1, // Name algorithm ObjectAttr.Restricted | // Storage keys must be restricted ObjectAttr.Decrypt | // Storage keys are Decrypt keys ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-duplicable (like 1.2) ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin, new byte[0], // No policy new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), new NullAsymScheme(), // No signature 2048, 0), // 2048-bit RSA new Tpm2bPublicKeyRsa()); // // Authorization for the key we are about to create // var srkAuth = new byte[0]; AuthValue childAuthVal = AuthValue.FromRandom(8); TssObject swKey = TssObject.CreateStorageParent(srkTemplate, childAuthVal); TpmPublic srkPublic; CreationData srkCreationData; TkCreation srkCreationTicket; byte[] srkCreationHash; // // Ask the TPM to create a new primary RSA/AES primary storage key // TpmHandle keyHandle = tpm[_ownerAuth].CreatePrimary( TpmHandle.RhOwner, // In the owner-hierarchy new SensitiveCreate(srkAuth, new byte[0]), // With this auth-value srkTemplate, // Describes key new byte[0], // For creation ticket new PcrSelection[0], // For creation ticket out srkPublic, // Out pubKey and attrs out srkCreationData, // Not used here out srkCreationHash, // Ibid out srkCreationTicket); // Ibid // // print out text-versions of the public key just created // Console.WriteLine("New SRK public key\n" + srkPublic.ToString()); // // The caller provides the handle for persistent keys // TpmHandle srkHandle = TpmHandle.Persistent(0x5000); // // Ae will make the "SRK" persistent in an NV-slot, so clean up anything // that is already there // tpm[_ownerAuth]._AllowErrors().EvictControl(TpmHandle.RhOwner, srkHandle, srkHandle); TpmRc lastError = tpm._GetLastResponseCode(); // // Make the SRK NV-resident // tpm[_ownerAuth].EvictControl(TpmHandle.RhOwner, keyHandle, srkHandle); Console.WriteLine("SRK is persistent now."); }
public TssKey() { publicPart = new TpmPublic(); privatePart = new byte[0]; }
/// <summary> /// This sample demonstrates the async interface to the TPM for selected slow operations. /// await-async is preferred when calling slow TPM functions on a UI-thread. Only a few TPM /// functions have an async-form. /// </summary> /// <param name="tpm">Reference to TPM object</param> /// <param name="Event">Synchronization object to signal calling function when we're done.</param> static async void PrimarySigningKeyAsync(Tpm2 tpm, AutoResetEvent Event) { // // The TPM needs a template that describes the parameters of the key // or other object to be created. The template below instructs the TPM // to create a new 2048-bit non-migratable signing key. // var keyTemplate = new TpmPublic(TpmAlgId.Sha1, // Name algorithm ObjectAttr.UserWithAuth | ObjectAttr.Sign | // Signing key ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-migratable ObjectAttr.SensitiveDataOrigin, new byte[0], // No policy new RsaParms(new SymDefObject(), new SchemeRsassa(TpmAlgId.Sha1), 2048, 0), new Tpm2bPublicKeyRsa()); // // Authorization for the key we are about to create // var keyAuth = new byte[] { 1, 2, 3 }; // // Ask the TPM to create a new primary RSA signing key // var newPrimary = await tpm[_ownerAuth].CreatePrimaryAsync( TpmHandle.RhOwner, // In the owner-hierarchy new SensitiveCreate(keyAuth, new byte[0]), // With this auth-value keyTemplate, // Describes key new byte[0], // For creation ticket new PcrSelection[0]); // For creation ticket // // Print out text-versions of the public key just created // Console.WriteLine("New public key\n" + newPrimary.outPublic.ToString()); // // Use the key to sign some data // byte[] message = Encoding.Unicode.GetBytes("ABC"); TpmHash dataToSign = TpmHash.FromData(TpmAlgId.Sha1, message); var sig = await tpm[keyAuth].SignAsync(newPrimary.objectHandle, // Handle of signing key dataToSign.HashData, // Data to sign new SchemeRsassa(TpmAlgId.Sha1), // Default scheme TpmHashCheck.NullHashCheck()); // // Print the signature. A different structure is returned for each // signing scheme, so cast the interface to our signature type. // var actualSig = (SignatureRsassa)sig; Console.WriteLine("Signature: " + BitConverter.ToString(actualSig.sig)); // // Clean up // tpm.FlushContext(newPrimary.objectHandle); // // Tell caller, we're done. // Event.Set(); }
public TssObject(TpmPublic thePublicPart, TpmPrivate thePrivatePart) { publicPart = thePublicPart; privatePart = thePrivatePart; }
/// <summary> /// Creates a duplication blob for the current key that can be Imported as a child /// of newParent. Three forms are possible. GetPlaintextDuplicationBlob() allows /// plaintext-import. This function enables duplication with and without an /// inner wrapper (depending on whether innerWrapper is null) /// </summary> /// <param name="newParent"></param> /// <param name="innerWrapper"></param> /// <param name="encryptedWrappingKey"></param> /// <returns></returns> public TpmPrivate GetDuplicationBlob( TpmPublic newParent, SymmCipher innerWrapper, out byte[] encryptedWrappingKey) { byte[] encSensitive; if (innerWrapper == null) { // No inner wrapper encSensitive = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation()); } else { byte[] sens = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation()); byte[] toHash = Globs.Concatenate(sens, GetName()); byte[] innerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData(publicPart.nameAlg, toHash)); byte[] innerData = Globs.Concatenate(innerIntegrity, sens); encSensitive = innerWrapper.Encrypt(innerData); } byte[] seed, encSecret; SymDefObject symDef = GetSymDef(newParent); using (AsymCryptoSystem newParentPubKey = AsymCryptoSystem.CreateFrom(newParent)) { switch (newParent.type) { case TpmAlgId.Rsa: // The seed should be the same size as the symmKey seed = Globs.GetRandomBytes((symDef.KeyBits + 7) / 8); encSecret = newParentPubKey.EncryptOaep(seed, DuplicateEncodingParms); break; case TpmAlgId.Ecc: EccPoint pubEphem; seed = newParentPubKey.EcdhGetKeyExchangeKey(DuplicateEncodingParms, newParent.nameAlg, out pubEphem); encSecret = Marshaller.GetTpmRepresentation(pubEphem); break; default: Globs.Throw <NotImplementedException>("GetDuplicationBlob: Unsupported algorithm"); encryptedWrappingKey = new byte[0]; return(new TpmPrivate()); } } encryptedWrappingKey = encSecret; byte[] symKey = KDF.KDFa(newParent.nameAlg, seed, "STORAGE", publicPart.GetName(), new byte[0], symDef.KeyBits); byte[] dupSensitive; using (SymmCipher enc2 = SymmCipher.Create(symDef, symKey)) { dupSensitive = enc2.Encrypt(encSensitive); } var npNameNumBits = CryptoLib.DigestSize(newParent.nameAlg) * 8; byte[] hmacKey = KDF.KDFa(newParent.nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], npNameNumBits); byte[] outerDataToHmac = Globs.Concatenate(dupSensitive, publicPart.GetName()); byte[] outerHmac = Marshaller.ToTpm2B(CryptoLib.HmacData(newParent.nameAlg, hmacKey, outerDataToHmac)); byte[] dupBlob = Globs.Concatenate(outerHmac, dupSensitive); return(new TpmPrivate(dupBlob)); }
/// <summary> /// Creates a *software* root key. The key will be random (not created from a seed). The key can be used /// as the root of a software hierarchy that can be translated into a duplication blob ready for import into /// a TPM. Depending on the type of key, the software root key can be a parent for other root keys that can /// comprise a migration group. The caller should specify necessary key parameters in Public. /// </summary> /// <returns></returns> public static TssObject CreateStorageParent(TpmPublic keyParameters, AuthValue authVal) { var newKey = new TssObject(); // Create a new asymmetric key from the supplied parameters IPublicIdUnion publicId; ISensitiveCompositeUnion sensitiveData = CreateSensitiveComposite(keyParameters, out publicId); // fill in the public data newKey.publicPart = keyParameters.Copy(); newKey.publicPart.unique = publicId; // Create the associated symmetric key - SymDefObject symDef = GetSymDef(keyParameters); byte[] symmKey; if (symDef.Algorithm != TpmAlgId.Null) { using (var symmCipher = SymmCipher.Create(symDef)) { symmKey = symmCipher.KeyData; } } else { symmKey = new byte[0]; } // Fill in the fields for the symmetric private-part of the asymmetric key var sens = new Sensitive(authVal.AuthVal, symmKey, sensitiveData); newKey.sensitivePart = sens; // And return the new key return newKey; }
public Tpm2CreatePrimaryResponse() { objectHandle = new TpmHandle(); outPublic = new TpmPublic(); creationData = new CreationData(); creationHash = new byte[0]; creationTicket = new TkCreation(); name = new byte[0]; }
/// <summary> /// Creates a duplication blob for the current key that can be Imported as a child /// of newParent. Three forms are possible. GetPlaintextDuplicationBlob() allows /// plaintext-import. This function enables duplication with and without an /// inner wrapper (depending on whether innerWrapper is null) /// </summary> /// <param name="newParent"></param> /// <param name="innerWrapper"></param> /// <param name="encryptedWrappingKey"></param> /// <returns></returns> public TpmPrivate GetDuplicationBlob( TpmPublic newParent, SymmCipher innerWrapper, out byte[] encryptedWrappingKey) { byte[] encSensitive; if (innerWrapper == null) { // No inner wrapper encSensitive = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation()); Transform(encSensitive); } else { byte[] sens = Marshaller.ToTpm2B(sensitivePart.GetTpmRepresentation()); byte[] toHash = Globs.Concatenate(sens, GetName()); Transform(toHash); byte[] innerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData(publicPart.nameAlg, toHash)); byte[] innerData = Globs.Concatenate(innerIntegrity, sens); Transform(innerData); encSensitive = innerWrapper.CFBEncrypt(innerData); Transform(encSensitive); } byte[] seed, encSecret; SymDefObject symDef = GetSymDef(newParent); using (AsymCryptoSystem newParentPubKey = AsymCryptoSystem.CreateFrom(newParent)) { switch (newParent.type) { case TpmAlgId.Rsa: // The seed should be the same size as the symmKey seed = Globs.GetRandomBytes((symDef.KeyBits + 7) / 8); encSecret = newParentPubKey.EncryptOaep(seed, DuplicateEncodingParms); break; case TpmAlgId.Ecc: EccPoint pubEphem; seed = newParentPubKey.EcdhGetKeyExchangeKey(DuplicateEncodingParms, newParent.nameAlg, out pubEphem); encSecret = Marshaller.GetTpmRepresentation(pubEphem); break; default: throw new NotImplementedException("activate crypto scheme not implemented"); } } Transform(seed); Transform(encSecret); encryptedWrappingKey = encSecret; byte[] symKey = KDF.KDFa(newParent.nameAlg, seed, "STORAGE", publicPart.GetName(), new byte[0], symDef.KeyBits); Transform(symKey); byte[] dupSensitive; using (SymmCipher enc2 = SymmCipher.Create(symDef, symKey)) { dupSensitive = enc2.CFBEncrypt(encSensitive); } Transform(dupSensitive); int npNameNumBits = CryptoLib.DigestSize(newParent.nameAlg) * 8; byte[] hmacKey = KDF.KDFa(newParent.nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], (uint)npNameNumBits); byte[] outerDataToHmac = Globs.Concatenate(dupSensitive, publicPart.GetName()); Transform(outerDataToHmac); byte[] outerHmac = Marshaller.ToTpm2B(CryptoLib.HmacData(newParent.nameAlg, hmacKey, outerDataToHmac)); Transform(outerHmac); byte[] dupBlob = Globs.Concatenate(outerHmac, dupSensitive); Transform(dupBlob); return new TpmPrivate(dupBlob); }
/// <summary> /// This is called from TpmPolicySigned when an external caller must sign the session data. /// </summary> /// <returns></returns> internal ISignatureUnion ExecuteSignerCallback(TpmPolicySigned ace, byte[] nonceTpm, out TpmPublic verificationKey) { if (SignerCallback == null) { throw new Exception("No policy signer callback installed."); } ISignatureUnion signature = SignerCallback(this, ace, nonceTpm, out verificationKey); return(signature); }
/// <summary> /// Create a new asymmetric key based on the parameters in keyParms. The resulting key data is returned in structures /// suitable for incorporation in a TPMT_PUBLIC and TPMS_SENSITIVE /// </summary> /// <param name="keyParms"></param> /// <param name="publicParms"></param> /// <returns></returns> internal static ISensitiveCompositeUnion CreateSensitiveComposite(TpmPublic keyParms, out IPublicIdUnion publicParms) { TpmAlgId keyAlgId = keyParms.type; ISensitiveCompositeUnion newSens; // Create the asymmetric key if (keyAlgId != TpmAlgId.Rsa) { throw new Exception("Algorithm not supported"); } var newKeyPair = new RawRsa((keyParms.parameters as RsaParms).keyBits); // Put the key bits into the required structure envelopes newSens = new Tpm2bPrivateKeyRsa(newKeyPair.Private); publicParms = new Tpm2bPublicKeyRsa(newKeyPair.Public); return newSens; }
/// <summary> /// Creates a duplication blob for the current key that can be Imported as a child /// of newParent. Three forms are possible. GetPlaintextDuplicationBlob() allows /// plaintext-import. This function enables duplication with and without an /// inner wrapper (depending on whether innerWrapper is null) /// </summary> /// <param name="newParent"></param> /// <param name="innerWrapper"></param> /// <param name="encSecret"></param> /// <returns></returns> public TpmPrivate GetDuplicationBlob( TpmPublic pubNewParent, SymCipher innerWrapper, out byte[] encSecret) { byte[] encSensitive; if (innerWrapper == null) { // No inner wrapper encSensitive = Marshaller.ToTpm2B(Sensitive.GetTpmRepresentation()); Transform(encSensitive); } else { byte[] sens = Marshaller.ToTpm2B(Sensitive.GetTpmRepresentation()); byte[] toHash = Globs.Concatenate(sens, GetName()); Transform(toHash); byte[] innerIntegrity = Marshaller.ToTpm2B(CryptoLib.HashData( Public.nameAlg, toHash)); byte[] innerData = Globs.Concatenate(innerIntegrity, sens); Transform(innerData); encSensitive = innerWrapper.Encrypt(innerData); Transform(encSensitive); } byte[] seed; SymDefObject symDef = GetSymDef(pubNewParent).Copy(); // TPM duplication procedures always use CFB mode symDef.Mode = TpmAlgId.Cfb; using (var swNewParent = AsymCryptoSystem.CreateFrom(pubNewParent)) { switch (pubNewParent.type) { case TpmAlgId.Rsa: // The seed should be the same size as the scheme hash LastSeed = seed = Globs.GetRandomBytes( CryptoLib.DigestSize(swNewParent.OaepHash)); encSecret = swNewParent.EncryptOaep(seed, DuplicateEncodingParms); break; case TpmAlgId.Ecc: EccPoint pubEphem; seed = swNewParent.EcdhGetKeyExchangeKey(DuplicateEncodingParms, pubNewParent.nameAlg, out pubEphem); encSecret = Marshaller.GetTpmRepresentation(pubEphem); break; default: Globs.Throw <NotImplementedException>( "GetDuplicationBlob: Unsupported algorithm"); encSecret = new byte[0]; return(new TpmPrivate()); } } Transform(seed); Transform(encSecret); byte[] symKey = KDF.KDFa(pubNewParent.nameAlg, seed, "STORAGE", Public.GetName(), new byte[0], symDef.KeyBits); Transform(symKey); byte[] dupSensitive; using (SymCipher enc2 = SymCipher.Create(symDef, symKey)) { if (enc2 == null) { return(null); } dupSensitive = enc2.Encrypt(encSensitive); } Transform(dupSensitive); var npNameNumBits = CryptoLib.DigestSize(pubNewParent.nameAlg) * 8; byte[] hmacKey = KDF.KDFa(pubNewParent.nameAlg, seed, "INTEGRITY", new byte[0], new byte[0], npNameNumBits); byte[] outerDataToHmac = Globs.Concatenate(dupSensitive, Public.GetName()); Transform(outerDataToHmac); byte[] outerHmac = Marshaller.ToTpm2B(CryptoLib.Hmac(pubNewParent.nameAlg, hmacKey, outerDataToHmac)); Transform(outerHmac); byte[] dupBlob = Globs.Concatenate(outerHmac, dupSensitive); Transform(dupBlob); return(new TpmPrivate(dupBlob)); }
/// <summary> /// Extract and return the SymDefObject that describes the associated symmetric algorithm that is used for key protection /// in storage keys. /// </summary> /// <param name="keyParms"></param> /// <returns></returns> internal static SymDefObject GetSymDef(TpmPublic keyParms) { TpmAlgId keyAlgId = keyParms.type; switch (keyAlgId) { case TpmAlgId.Rsa: var rsaParms = (RsaParms)keyParms.parameters; return rsaParms.symmetric; case TpmAlgId.Ecc: var eccParms = (EccParms)keyParms.parameters; return eccParms.symmetric; default: throw new Exception("Unsupported algorithm"); } }
/// <summary> /// Create a sealed-object primary that can be accessed with the given policy. SHA256 is assumed. /// </summary> /// <param name="tpm"></param> /// <param name="dataToSeal"></param> /// <param name="authValue"></param> /// <param name="policy"></param> /// <returns></returns> private static TpmHandle CreateSealedPrimaryObject(Tpm2 tpm, byte[] dataToSeal, byte[] authValue, byte[] policy) { ObjectAttr attrs = ObjectAttr.FixedTPM | ObjectAttr.FixedParent; if (authValue != null) { attrs |= ObjectAttr.UserWithAuth; } byte[] policyVal = policy ?? new byte[0]; var sealedInPublic = new TpmPublic(TpmAlgId.Sha256, attrs, policyVal, new KeyedhashParms(new NullSchemeKeyedhash()), new Tpm2bDigestKeyedhash()); // // Envelope for sealed data and auth // byte[] authVal = authValue ?? new byte[0]; var sealedInSensitive = new SensitiveCreate(authVal, dataToSeal); TkCreation creationTicket; byte[] creationHashSealed; TpmPublic sealedPublic; CreationData sealedCreationData; // // AuthValue encapsulates an authorization value: essentially a byte-array. // OwnerAuth is the owner authorization value of the TPM-under-test. We // assume that it (and other) auths are set to the default (null) value. // If running on a real TPM, which has been provisioned by Windows, this // value will be different. An administrator can retrieve the owner // authorization value from the registry. // var ownerAuth = new AuthValue(); // // Ask the TPM to create a primary containing the "sealed" data // TpmHandle primHandle = tpm[ownerAuth].CreatePrimary(TpmHandle.RhOwner, sealedInSensitive, sealedInPublic, new byte[0], new PcrSelection[0], out sealedPublic, out sealedCreationData, out creationHashSealed, out creationTicket); return primHandle; }
public Tpm2bPublic() { publicArea = new TpmPublic(); }