Ejemplo n.º 1
0
        private static unsafe byte[] EncodePublicKey(PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            // Construct CERT_PUBLIC_KEY_INFO2 in unmanged memory from given encoded blobs.
            SafeLocalAllocHandle publicKeyInfo = EncodePublicKey(key);

            CAPI.CERT_PUBLIC_KEY_INFO2 *pPublicKeyInfo = (CAPI.CERT_PUBLIC_KEY_INFO2 *)publicKeyInfo.DangerousGetHandle();

            byte [] buffer     = new byte[20];
            byte [] identifier = null;

            fixed(byte *pBuffer = buffer)
            {
                uint   cbData = (uint)buffer.Length;
                IntPtr pbData = new IntPtr(pBuffer);

                try {
                    if ((X509SubjectKeyIdentifierHashAlgorithm.Sha1 == algorithm) ||
                        (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm))
                    {
                        //+=================================================================
                        // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of
                        // the value of the BIT STRING subjectPublicKey (excluding the tag,
                        // length, and number of unused bits).
                        if (!CAPI.CryptHashCertificate(
                                IntPtr.Zero,            // hCryptProv
                                CAPI.CALG_SHA1,
                                0,                      // dwFlags,
                                pPublicKeyInfo->PublicKey.pbData,
                                pPublicKeyInfo->PublicKey.cbData,
                                pbData,
                                new IntPtr(&cbData)))
                        {
                            throw new CryptographicException(Marshal.GetHRForLastWin32Error());
                        }
                    }
                    //+=================================================================
                    // Microsoft convention: The keyIdentifier is composed of the
                    // 160-bit SHA-1 hash of the encoded subjectPublicKey BITSTRING
                    // (including the tag, length, and number of unused bits).
                    else if (X509SubjectKeyIdentifierHashAlgorithm.CapiSha1 == algorithm)
                    {
                        if (!CAPI.CryptHashPublicKeyInfo(
                                IntPtr.Zero,            // hCryptProv
                                CAPI.CALG_SHA1,
                                0,                      // dwFlags,
                                CAPI.X509_ASN_ENCODING,
                                new IntPtr(pPublicKeyInfo),
                                pbData,
                                new IntPtr(&cbData)))
                        {
                            throw new CryptographicException(Marshal.GetHRForLastWin32Error());
                        }
                    }
                    else
                    {
                        throw new ArgumentException("algorithm");
                    }

                    //+=================================================================
                    // (2) The keyIdentifier is composed of a four bit type field with
                    //  the value 0100 followed by the least significant 60 bits of the
                    //  SHA-1 hash of the value of the BIT STRING subjectPublicKey
                    // (excluding the tag, length, and number of unused bit string bits)
                    if (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm)
                    {
                        identifier = new byte[8];
                        Array.Copy(buffer, buffer.Length - 8, identifier, 0, identifier.Length);
                        identifier[0] &= 0x0f;
                        identifier[0] |= 0x40;
                    }
                    else
                    {
                        identifier = buffer;
                        // return the meaningful part only
                        if (buffer.Length > (int)cbData)
                        {
                            identifier = new byte[cbData];
                            Array.Copy(buffer, 0, identifier, 0, identifier.Length);
                        }
                    }
                } finally {
                    publicKeyInfo.Dispose();
                }
            }

            return(EncodeExtension(identifier));
        }