Esempio n. 1
0
        public async Task <(X509Certificate2 identityCert, X509Certificate2[] certChain)> GetIdentityCertificateAsync(TimeSpan validity, CancellationToken token = default)
        {
            var request = new IdentityCertificateRequest
            {
                Expiration = DateTime.UtcNow.Add(validity),
            };

            string requestString = JsonConvert.SerializeObject(request, Formatting.None, this.jsonSettings);

            using (var content = new StringContent(requestString, Encoding.UTF8, "application/json"))
                using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, this.postIdentityCertificateRequestUri)
                {
                    Content = content
                })
                    using (HttpResponseMessage httpResponse = await this.httpClient.SendAsync(httpRequest, token))
                    {
                        string responsePayload = await httpResponse.Content.ReadAsStringAsync();

                        if (httpResponse.StatusCode == HttpStatusCode.Created)
                        {
                            CertificateResponse cr = JsonConvert.DeserializeObject <CertificateResponse>(responsePayload, this.jsonSettings);
                            return(this.CreateX509Certificates(cr));
                        }

                        throw new InvalidOperationException($"Failed to retrieve identity certificate from IoTEdge security daemon. StatusCode={httpResponse.StatusCode} ReasonPhrase='{httpResponse.ReasonPhrase}' ResponsePayload='{responsePayload}' Request={requestString} This={this}");
                    }
        }
Esempio n. 2
0
        private (X509Certificate2 primaryCert, X509Certificate2[] certChain) CreateX509Certificates(CertificateResponse cr, [CallerMemberName] string callerMemberName = default)
        {
            Validate.ArgumentNotNullOrEmpty(cr.Certificate, nameof(cr.Certificate));
            Validate.ArgumentNotNull(cr.Expiration, nameof(cr.Expiration));
            Validate.ArgumentNotNull(cr.PrivateKey, nameof(cr.PrivateKey));
            Validate.ArgumentNotNull(cr.PrivateKey.Type, nameof(cr.PrivateKey.Type));
            Validate.ArgumentNotNull(cr.PrivateKey.Bytes, nameof(cr.PrivateKey.Bytes));

            string[] rawCerts = ParseCertificateResponse(cr.Certificate);
            if (rawCerts.Length == 0 ||
                string.IsNullOrWhiteSpace(rawCerts[0]))
            {
                throw new InvalidOperationException($"Failed to retrieve certificate from IoTEdge Security daemon for {callerMemberName}. Reason: Security daemon returned an empty response.");
            }

            string primaryCert = rawCerts[0];

            X509Certificate2[] certChain = ConvertToX509(rawCerts.Skip(1));

            RsaPrivateCrtKeyParameters keyParams = null;

            var         chainCertEntries = new List <X509CertificateEntry>();
            Pkcs12Store store            = new Pkcs12StoreBuilder().Build();

            // note: the seperator between the certificate and private key is added for safety to delineate the cert and key boundary
            using (var sr = new StringReader(primaryCert + "\r\n" + cr.PrivateKey.Bytes))
            {
                var    pemReader = new PemReader(sr);
                object certObject;
                while ((certObject = pemReader.ReadObject()) != null)
                {
                    if (certObject is Org.BouncyCastle.X509.X509Certificate x509Cert)
                    {
                        chainCertEntries.Add(new X509CertificateEntry(x509Cert));
                    }

                    // when processing certificates generated via openssl certObject type is of AsymmetricCipherKeyPair
                    if (certObject is AsymmetricCipherKeyPair ackp)
                    {
                        certObject = ackp.Private;
                    }

                    if (certObject is RsaPrivateCrtKeyParameters rpckp)
                    {
                        keyParams = rpckp;
                    }
                }
            }

            if (keyParams == null)
            {
                throw new InvalidOperationException($"Private key was not found for {callerMemberName}");
            }

            store.SetKeyEntry(this.ModuleId, new AsymmetricKeyEntry(keyParams), chainCertEntries.ToArray());
            using (var ms = new MemoryStream())
            {
                store.Save(ms, Array.Empty <char>(), new SecureRandom());
                var x509PrimaryCert = new X509Certificate2(ms.ToArray());
                return(x509PrimaryCert, certChain);
            }
        }