Example #1
0
        public static (ushort size, byte[] name) NameFromTPM2BName(byte[] ab, ref int offset)
        {
            // TCG TPM Rev 2.0, part 2, structures, section 10.5.3, TPM2B_NAME
            // This buffer holds a Name for any entity type.
            // The type of Name in the structure is determined by context and the size parameter.
            var    totalBytes = AuthDataHelper.GetSizedByteArray(ab, ref offset, 2);
            ushort totalSize  = 0;

            if (null != totalBytes)
            {
                totalSize = BitConverter.ToUInt16(totalBytes.ToArray().Reverse().ToArray(), 0);
            }
            ushort size  = 0;
            var    bytes = AuthDataHelper.GetSizedByteArray(ab, ref offset, 2);

            if (null != bytes)
            {
                size = BitConverter.ToUInt16(bytes.ToArray().Reverse().ToArray(), 0);
            }
            // If size is four, then the Name is a handle.
            if (4 == size)
            {
                throw new VerificationException("Unexpected handle in TPM2B_NAME");
            }
            // If size is zero, then no Name is present.
            if (0 == size)
            {
                throw new VerificationException("Unexpected no name found in TPM2B_NAME");
            }
            // Otherwise, the size shall be the size of a TPM_ALG_ID plus the size of the digest produced by the indicated hash algorithm.
            byte[] name = null;
            if (Enum.IsDefined(typeof(TpmAlg), size))
            {
                var tpmalg = (TpmAlg)size;
                if (tpmAlgToDigestSizeMap.ContainsKey(tpmalg))
                {
                    name = AuthDataHelper.GetSizedByteArray(ab, ref offset, tpmAlgToDigestSizeMap[tpmalg]);
                }
                else
                {
                    throw new VerificationException("TPM_ALG_ID found in TPM2B_NAME not acceptable hash algorithm");
                }
            }
            else
            {
                throw new VerificationException("Invalid TPM_ALG_ID found in TPM2B_NAME");
            }

            if (totalSize != bytes.Length + name.Length)
            {
                throw new VerificationException("Unexpected extra bytes found in TPM2B_NAME");
            }
            return(size, name);
        }
Example #2
0
        public CertInfo(byte[] certInfo)
        {
            if (null == certInfo || 0 == certInfo.Length)
            {
                throw new VerificationException("Malformed certInfo bytes");
            }
            Raw = certInfo;
            var offset = 0;

            Magic = AuthDataHelper.GetSizedByteArray(certInfo, ref offset, 4);
            if (0xff544347 != BitConverter.ToUInt32(Magic.ToArray().Reverse().ToArray(), 0))
            {
                throw new VerificationException("Bad magic number " + BitConverter.ToString(Magic).Replace("-", ""));
            }
            Type = AuthDataHelper.GetSizedByteArray(certInfo, ref offset, 2);
            if (0x8017 != BitConverter.ToUInt16(Type.ToArray().Reverse().ToArray(), 0))
            {
                throw new VerificationException("Bad structure tag " + BitConverter.ToString(Type).Replace("-", ""));
            }
            QualifiedSigner = AuthDataHelper.GetSizedByteArray(certInfo, ref offset);
            ExtraData       = AuthDataHelper.GetSizedByteArray(certInfo, ref offset);
            if (null == ExtraData || 0 == ExtraData.Length)
            {
                throw new VerificationException("Bad extraData in certInfo");
            }
            Clock                       = AuthDataHelper.GetSizedByteArray(certInfo, ref offset, 8);
            ResetCount                  = AuthDataHelper.GetSizedByteArray(certInfo, ref offset, 4);
            RestartCount                = AuthDataHelper.GetSizedByteArray(certInfo, ref offset, 4);
            Safe                        = AuthDataHelper.GetSizedByteArray(certInfo, ref offset, 1);
            FirmwareVersion             = AuthDataHelper.GetSizedByteArray(certInfo, ref offset, 8);
            var(size, name)             = NameFromTPM2BName(certInfo, ref offset);
            Alg                         = size; // TPM_ALG_ID
            AttestedName                = name;
            AttestedQualifiedNameBuffer = AuthDataHelper.GetSizedByteArray(certInfo, ref offset);
            if (certInfo.Length != offset)
            {
                throw new VerificationException("Leftover bits decoding certInfo");
            }
        }
Example #3
0
        public PubArea(byte[] pubArea)
        {
            Raw = pubArea;
            var offset = 0;

            // TPMI_ALG_PUBLIC
            Type = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 2);
            var tpmalg = (TpmAlg)Enum.Parse(typeof(TpmAlg), BitConverter.ToUInt16(Type.Reverse().ToArray(), 0).ToString());

            // TPMI_ALG_HASH
            Alg = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 2);

            // TPMA_OBJECT, attributes that, along with type, determine the manipulations of this object
            Attributes = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 4);

            // TPM2B_DIGEST, optional policy for using this key, computed using the alg of the object
            Policy = AuthDataHelper.GetSizedByteArray(pubArea, ref offset);

            // TPMU_PUBLIC_PARMS
            Symmetric = null;
            Scheme    = null;

            if (TpmAlg.TPM_ALG_KEYEDHASH == tpmalg)
            {
                throw new VerificationException("TPM_ALG_KEYEDHASH not yet supported");
            }
            if (TpmAlg.TPM_ALG_SYMCIPHER == tpmalg)
            {
                throw new VerificationException("TPM_ALG_SYMCIPHER not yet supported");
            }

            // TPMS_ASYM_PARMS, for TPM_ALG_RSA and TPM_ALG_ECC
            if (TpmAlg.TPM_ALG_RSA == tpmalg || TpmAlg.TPM_ALG_ECC == tpmalg)
            {
                Symmetric = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 2);
                Scheme    = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 2);
            }

            // TPMI_RSA_KEY_BITS, number of bits in the public modulus
            KeyBits = null;
            // The public exponent, a prime number greater than 2. When zero, indicates that the exponent is the default of 2^16 + 1
            Exponent = 0;

            if (TpmAlg.TPM_ALG_RSA == tpmalg)
            {
                KeyBits = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 2);
                var tmp = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 4);
                if (null != tmp)
                {
                    Exponent = BitConverter.ToUInt32(tmp.ToArray(), 0);
                    if (0 == Exponent)
                    {
                        Exponent = Convert.ToUInt32(Math.Pow(2, 16) + 1);
                    }
                }
            }

            // TPMI_ECC_CURVE
            CurveID = null;

            // TPMT_KDF_SCHEME, an optional key derivation scheme for generating a symmetric key from a Z value
            // If the kdf  parameter associated with curveID is not TPM_ALG_NULL then this is required to be NULL.
            // NOTE There are currently no commands where this parameter has effect and, in the reference code, this field needs to be set to TPM_ALG_NULL.
            KDF = null;

            if (TpmAlg.TPM_ALG_ECC == tpmalg)
            {
                CurveID = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 2);
                KDF     = AuthDataHelper.GetSizedByteArray(pubArea, ref offset, 2);
            }

            // TPMU_PUBLIC_ID
            Unique = AuthDataHelper.GetSizedByteArray(pubArea, ref offset);
            if (pubArea.Length != offset)
            {
                throw new VerificationException("Leftover bytes decoding pubArea");
            }
        }
Example #4
0
        public static byte[] GetASN1ObjectAtIndex(byte[] attExtBytes, int index)
        {
            // https://developer.android.com/training/articles/security-key-attestation#certificate_schema
            // This function returns an entry from the KeyDescription at index
            if (null == attExtBytes || 0 == attExtBytes.Length || attExtBytes.Length > ushort.MaxValue)
            {
                throw new Fido2VerificationException("Invalid attExtBytes signature value");
            }
            var offset      = 0;
            var derSequence = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, 1);

            // expecting to start with 0x30 indicating SEQUENCE
            if (null == derSequence || 0x30 != derSequence[0])
            {
                throw new Fido2VerificationException("attExtBytes signature not a valid DER sequence");
            }

            // next is length of all the items in the sequence
            var dataLen = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, 1);

            if (null == dataLen)
            {
                throw new Fido2VerificationException("attExtBytes signature has invalid length");
            }

            // if data is more than 127 bytes, the length is encoded in long form
            // TODO : Why is longLen never used ?
            var longForm = (dataLen[0] > 0x7f);
            var longLen  = 0;

            if (true == longForm)
            {
                var longLenByte = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, 1);
                if (null == longLenByte)
                {
                    throw new Fido2VerificationException("attExtBytes signature has invalid long form length");
                }
                longLen  = longLenByte[0];
                longLen &= (1 << 7);
            }

            // walk through each sequence entry until we get to the requested index
            for (var i = 0; i < index; i++)
            {
                var derId = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, 1);
                if (null == derId)
                {
                    throw new Fido2VerificationException("Ran out of bytes in attExtBytes sequence without finding the first octet string");
                }
                var lenValue = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, 1);
                if (null == lenValue)
                {
                    throw new Fido2VerificationException("attExtBytes lenValue invalid");
                }
                if (0 < lenValue[0])
                {
                    var value = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, lenValue[0]);
                    if (null == value)
                    {
                        throw new Fido2VerificationException("Ran out of bytes in attExtBytes sequence without finding the first octet string");
                    }
                }
            }
            // skip the identifier of the requested item
            var asn1Id = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, 1);

            if (null == asn1Id)
            {
                throw new Fido2VerificationException("Ran out of bytes in attExtBytes sequence without finding the first octet string");
            }
            // get length of requested item
            var lenAsn1value = AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, 1);

            if (null == lenAsn1value)
            {
                throw new Fido2VerificationException("lenAttestationChallenge version length invalid");
            }
            // return byte array containing the requested item
            return(AuthDataHelper.GetSizedByteArray(attExtBytes, ref offset, lenAsn1value[0]));
        }