简体   繁体   中英

Azure IoT Hub Unauthorized Access for Additional Devices

I have an issue attempting to register a second device through DPS to an IoT Hub using x509 certificates. My root certificate authority is present and validated on both the DPS and IoT Hub (generated through openssl). As for the client side certificate, I'm generating it once the application starts (if to doesn't already exist) in the below code. What's bothering me is every single device gets enrolled into Azure DPS correctly but only the FIRST device gets authorized and registered. Is it possibly something I'm doing during my client side certificate creation that is messing it up? Also the error is found in this line during device registration to the IoT Hub:

DeviceRegistrationResult result = await provisioningDeviceClient.RegisterAsync().ConfigureAwait(false);

Added error:

2019/12/16 09:37:38.309|ERROR| Error found attempting to start service The device failed to register @ the IoT Hub : The device failes to provision correctly: AMQP transport exception | Tidel.DeviceAgent.DeviceAgent |

CLIENT SIDE CERTIFICATE GENERATION

        X509Certificate2 caRootCertificate;
        X509Store caStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
        caStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

        X509Certificate2Collection signerCollection = (X509Certificate2Collection)caStore.Certificates.Find(X509FindType.FindByIssuerName, "CERTNAME", true);

        caStore.Close();

        if (signerCollection.Count != 0)
        {
            caRootCertificate = signerCollection[0];

            using (var rsa = RSA.Create())
            {
                rsa.KeySize = 2048;

                var clientCertificateRequest = new CertificateRequest($"CN={_writableOptions.Value.RegistrationId}", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

                clientCertificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));

                var issuerSubjectKey = caRootCertificate.Extensions["Subject Key Identifier"].RawData;
                var segment = new ArraySegment<byte>(issuerSubjectKey, 2, issuerSubjectKey.Length - 2);
                var authorityKeyIdentifier = new byte[segment.Count + 4];

                authorityKeyIdentifier[0] = 0x30;
                authorityKeyIdentifier[1] = 0x16;
                authorityKeyIdentifier[2] = 0x80;
                authorityKeyIdentifier[3] = 0x14; 
                segment.CopyTo(authorityKeyIdentifier, 4);
                clientCertificateRequest.CertificateExtensions.Add(new X509Extension("2.5.29.35", authorityKeyIdentifier, false));


                var sanBuilder = new SubjectAlternativeNameBuilder();
                sanBuilder.AddDnsName(_writableOptions.Value.RegistrationId);
                var sanExtension = sanBuilder.Build();
                clientCertificateRequest.CertificateExtensions.Add(sanExtension);

                clientCertificateRequest.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.2") }, false));
                clientCertificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(clientCertificateRequest.PublicKey, false));

                var notBefore = DateTimeOffset.UtcNow.AddDays(-1);

                if (notBefore < caRootCertificate.NotBefore)
                {
                    notBefore = new DateTimeOffset(caRootCertificate.NotBefore);
                }

                var notAfter = DateTimeOffset.UtcNow.AddDays(365);

                if (notAfter > caRootCertificate.NotAfter)
                {
                    notAfter = new DateTimeOffset(caRootCertificate.NotAfter);
                }

                var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                var unixTime = Convert.ToInt64((DateTime.UtcNow - epoch).TotalSeconds);
                var serial = BitConverter.GetBytes(unixTime);

                using (var cert = clientCertificateRequest.Create(caRootCertificate, notBefore, notAfter, serial))
                {
                    X509Certificate2 client = cert.CopyWithPrivateKey(rsa);

                    return await Task.FromResult(client);
                }
            }
        }
        else
        {
            throw new FileNotFoundException($"Could not find a root certificate.");
        }

DEVICE ENROLLMENT TO DPS

    Attestation attestation = X509Attestation.CreateFromClientCertificates(new X509Certificate2(certificate.Export(X509ContentType.Cert)));

    IndividualEnrollment individualEnrollment = new IndividualEnrollment(_writableOptions.Value.RegistrationId, attestation)
    {
        DeviceId = _writableOptions.Value.DeviceId,
        ProvisioningStatus = ProvisioningStatus.Enabled
    };

    individualEnrollmentResult = await _provisioningServiceClient.CreateOrUpdateIndividualEnrollmentAsync(individualEnrollment).ConfigureAwait(false);

DEVICE REGISTRATION TO IOT HUB

using (var certificatePassword = new X509Certificate2(certificate.GetRawCertData(), _writableOptions.Value.CertPass))
{
    using (var security = new SecurityProviderX509Certificate(certificatePassword))
    {
        using (var transport = new ProvisioningTransportHandlerAmqp(TransportFallbackType.TcpOnly))
        {
            ProvisioningDeviceClient provisioningDeviceClient = ProvisioningDeviceClient.Create(_writableOptions.Value.AzureEndpoint, _writableOptions.Value.IdScope, security, transport);
            DeviceRegistrationResult result = await provisioningDeviceClient.RegisterAsync().ConfigureAwait(false);
            IAuthenticationMethod authenticationMethod = new DeviceAuthenticationWithX509Certificate(result.DeviceId, certificate);
            DeviceClient deviceClient = DeviceClient.Create(result.AssignedHub, authenticationMethod, TransportType.Amqp_Tcp_Only);

            return await Task.FromResult(deviceClient);
       }
     }
}

I figured out the issue. When the certificate was generated in the store, I was using FindByIssuerName to locate the certificate.

X509Certificate2Collection signerCollection = (X509Certificate2Collection)caStore.Certificates.Find(X509FindType.FindByIssuerName, "CERTNAME", true);

After investigating further, there were TWO certificates with the exact same name in the store. The issue: MMC snap-in was only showing one certificate. After looking around, it was suggested somewhere to run a storerepair command on the store. After running the store repair command, I could then see both certificates in MMC and was able to remove the offending certificate preventing the valid one from being detected.

Windows Version: Windows Embedded 8.1 Industry Pro

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM