public virtual Task VerifySigningRequestAsync( ApplicationRecordDataType application, byte[] certificateRequest) { try { var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest); if (!pkcs10CertificationRequest.Verify()) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR signature invalid."); } var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); var altNameExtension = GetAltNameExtensionFromCSRInfo(info); if (altNameExtension != null) { if (altNameExtension.Uris.Count > 0) { if (!altNameExtension.Uris.Contains(application.ApplicationUri)) { throw new ServiceResultException(StatusCodes.BadCertificateUriInvalid, "CSR AltNameExtension does not match " + application.ApplicationUri); } } } return(Task.CompletedTask); } catch (Exception ex) { if (ex is ServiceResultException) { throw ex as ServiceResultException; } throw new ServiceResultException(StatusCodes.BadInvalidArgument, ex.Message); } }
protected override ValidationResult IsValid(object value, ValidationContext validationContext) { CreateSigningRequestUploadApiModel request = (CreateSigningRequestUploadApiModel)validationContext.ObjectInstance; var errorList = new List <string>(); if (request.CertificateRequestFile == null && String.IsNullOrWhiteSpace(request.ApiModel.CertificateRequest)) { errorList.Add(nameof(request.CertificateRequestFile)); errorList.Add("ApiModel.CertificateRequest"); return(new ValidationResult("At least one CSR field is required.", errorList)); } if (request.CertificateRequestFile != null && !String.IsNullOrWhiteSpace(request.ApiModel.CertificateRequest)) { errorList.Add(nameof(request.CertificateRequestFile)); errorList.Add("ApiModel.CertificateRequest"); return(new ValidationResult("Only one CSR field is required.", errorList)); } byte[] certificateRequest = null; if (request.ApiModel.CertificateRequest != null) { errorList.Add("ApiModel.CertificateRequest"); try { const string certRequestPemHeader = "-----BEGIN CERTIFICATE REQUEST-----"; const string certRequestPemFooter = "-----END CERTIFICATE REQUEST-----"; if (request.ApiModel.CertificateRequest.Contains(certRequestPemHeader, StringComparison.OrdinalIgnoreCase)) { var strippedCertificateRequest = request.ApiModel.CertificateRequest.Replace(certRequestPemHeader, "", StringComparison.OrdinalIgnoreCase); strippedCertificateRequest = strippedCertificateRequest.Replace(certRequestPemFooter, "", StringComparison.OrdinalIgnoreCase); certificateRequest = Convert.FromBase64String(strippedCertificateRequest); } else { certificateRequest = Convert.FromBase64String(request.ApiModel.CertificateRequest); } } catch { return(new ValidationResult("Cannot decode base64 encoded CSR.", errorList)); } } if (request.CertificateRequestFile != null) { errorList.Add(nameof(request.CertificateRequestFile)); try { using (var memoryStream = new MemoryStream()) { request.CertificateRequestFile.CopyToAsync(memoryStream).Wait(); certificateRequest = memoryStream.ToArray(); } } catch { errorList.Add(nameof(request.CertificateRequestFile)); return(new ValidationResult("Invalid CSR file.", errorList)); } } if (certificateRequest != null) { try { var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest); if (!pkcs10CertificationRequest.Verify()) { return(new ValidationResult("CSR signature invalid.", errorList)); } var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); var altNameExtension = GetAltNameExtensionFromCSRInfo(info); if (altNameExtension != null && altNameExtension.Uris.Count > 0) { if (!altNameExtension.Uris.Contains(request.ApplicationUri)) { return(new ValidationResult(altNameExtension.Uris[0] + " doesn't match the ApplicationUri.", errorList)); } } else { return(new ValidationResult("The CSR does not contain a valid Application Uri.", errorList)); } } catch { return(new ValidationResult("CSR decoding failed. Invalid data?", errorList)); } } return(ValidationResult.Success); }
public virtual async Task <X509Certificate2> SigningRequestAsync( ApplicationRecordDataType application, string[] domainNames, byte[] certificateRequest) { try { var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest); if (!pkcs10CertificationRequest.Verify()) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR signature invalid."); } var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); var altNameExtension = GetAltNameExtensionFromCSRInfo(info); if (altNameExtension != null) { if (altNameExtension.Uris.Count > 0) { if (!altNameExtension.Uris.Contains(application.ApplicationUri)) { throw new ServiceResultException(StatusCodes.BadCertificateUriInvalid, "CSR AltNameExtension does not match " + application.ApplicationUri); } } if (altNameExtension.IPAddresses.Count > 0 || altNameExtension.DomainNames.Count > 0) { var domainNameList = new List <string>(); domainNameList.AddRange(altNameExtension.DomainNames); domainNameList.AddRange(altNameExtension.IPAddresses); domainNames = domainNameList.ToArray(); } } DateTime yesterday = DateTime.UtcNow.AddDays(-1); using (var signingKey = await LoadSigningKeyAsync(Certificate, string.Empty)) { return(CertificateFactory.CreateCertificate( null, null, null, application.ApplicationUri ?? "urn:ApplicationURI", application.ApplicationNames.Count > 0 ? application.ApplicationNames[0].Text : "ApplicationName", info.Subject.ToString(), domainNames, Configuration.DefaultCertificateKeySize, yesterday, Configuration.DefaultCertificateLifetime, Configuration.DefaultCertificateHashSize, false, signingKey, info.SubjectPublicKeyInfo.GetEncoded())); } } catch (Exception ex) { if (ex is ServiceResultException) { throw ex as ServiceResultException; } throw new ServiceResultException(StatusCodes.BadInvalidArgument, ex.Message); } }
public virtual async Task <X509Certificate2> SigningRequestAsync( ApplicationRecordDataType application, string[] domainNames, byte[] certificateRequest) { try { var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest); if (!pkcs10CertificationRequest.Verify()) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR signature invalid."); } var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); var altNameExtension = GetAltNameExtensionFromCSRInfo(info); if (altNameExtension != null) { if (altNameExtension.Uris.Count > 0) { if (!altNameExtension.Uris.Contains(application.ApplicationUri)) { throw new ServiceResultException(StatusCodes.BadCertificateUriInvalid, "CSR AltNameExtension does not match " + application.ApplicationUri); } } if (altNameExtension.IPAddresses.Count > 0 || altNameExtension.DomainNames.Count > 0) { var domainNameList = new List <string>(); domainNameList.AddRange(altNameExtension.DomainNames); domainNameList.AddRange(altNameExtension.IPAddresses); domainNames = domainNameList.ToArray(); } } DateTime yesterday = DateTime.Today.AddDays(-1); using (var signingKey = await LoadSigningKeyAsync(Certificate, string.Empty).ConfigureAwait(false)) { return(CertificateFactory.CreateCertificate( application.ApplicationUri, null, info.Subject.ToString(), domainNames) .SetNotBefore(yesterday) .SetLifeTime(Configuration.DefaultCertificateLifetime) .SetHashAlgorithm(X509Utils.GetRSAHashAlgorithmName(Configuration.DefaultCertificateHashSize)) .SetIssuer(signingKey) .SetRSAPublicKey(info.SubjectPublicKeyInfo.GetEncoded()) .CreateForRSA()); } } catch (Exception ex) { if (ex is ServiceResultException) { throw ex as ServiceResultException; } throw new ServiceResultException(StatusCodes.BadInvalidArgument, ex.Message); } }
/// <summary> /// Creates a new signed application certificate in group id. /// </summary> /// <remarks> /// The key for the certificate is created in KeyVault, then exported. /// In order to deleted the created key, the impersonated user needs /// create, get and delete rights for KeyVault certificates /// </remarks> public async Task <X509Certificate2> CreateSignedKeyPairCertAsync( string caCertId, X509Certificate2 issuerCert, string applicationUri, string applicationName, string subjectName, string[] domainNames, DateTime notBefore, DateTime notAfter, int keySize, int hashSize, KeyVaultSignatureGenerator generator, string authorityInformationAccess, CancellationToken ct = default) { CertificateOperation createResult = null; var certName = KeyStoreName(caCertId, Guid.NewGuid().ToString()); try { // policy unknown issuer, new key, exportable var policyUnknownNewExportable = CreateCertificatePolicy(subjectName, keySize, false, false, true); var attributes = CreateCertificateAttributes(notBefore, notAfter); // create the CSR createResult = await _keyVaultClient.CreateCertificateAsync( _vaultBaseUrl, certName, policyUnknownNewExportable, attributes, null, ct) .ConfigureAwait(false); if (createResult.Csr == null) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "Failed to read CSR from CreateCertificate."); } // decode the CSR and verify consistency var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(createResult.Csr); var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); if (createResult.Csr == null || pkcs10CertificationRequest == null || !pkcs10CertificationRequest.Verify()) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "Invalid CSR."); } // create the self signed app cert var publicKey = KeyVaultCertFactory.GetRSAPublicKey(info.SubjectPublicKeyInfo); var signedcert = await KeyVaultCertFactory.CreateSignedCertificate( applicationUri, applicationName, subjectName, domainNames, (ushort)keySize, notBefore, notAfter, (ushort)hashSize, issuerCert, publicKey, generator, extensionUrl : authorityInformationAccess); // merge signed cert with keystore var mergeResult = await _keyVaultClient.MergeCertificateAsync( _vaultBaseUrl, certName, new X509Certificate2Collection(signedcert) ); X509Certificate2 keyPair = null; var secret = await _keyVaultClient.GetSecretAsync(mergeResult.SecretIdentifier.Identifier, ct); if (secret.ContentType == CertificateContentType.Pfx) { var certBlob = Convert.FromBase64String(secret.Value); keyPair = CertificateFactory.CreateCertificateFromPKCS12(certBlob, string.Empty); } else if (secret.ContentType == CertificateContentType.Pem) { Encoding encoder = Encoding.UTF8; var privateKey = encoder.GetBytes(secret.Value.ToCharArray()); keyPair = CertificateFactory.CreateCertificateWithPEMPrivateKey(signedcert, privateKey, string.Empty); } return(keyPair); } catch { throw new ServiceResultException(StatusCodes.BadInternalError, "Failed to create new key pair certificate"); } finally { try { var deletedCertBundle = await _keyVaultClient.DeleteCertificateAsync(_vaultBaseUrl, certName, ct); await _keyVaultClient.PurgeDeletedCertificateAsync(_vaultBaseUrl, certName, ct); } catch { // intentionally fall through, purge may fail } } }
/// <summary> /// Creates a new Root CA certificate in group id, tags it for trusted or issuer store. /// </summary> public async Task <X509Certificate2> CreateCACertificateAsync( string id, string subject, DateTime notBefore, DateTime notAfter, int keySize, int hashSize, bool trusted, string crlDistributionPoint = null, CancellationToken ct = default) { try { // delete pending operations await _keyVaultClient.DeleteCertificateOperationAsync(_vaultBaseUrl, id); } catch { // intentionally ignore errors } string caTempCertIdentifier = null; try { // policy self signed, new key var policySelfSignedNewKey = CreateCertificatePolicy(subject, keySize, true, false); var tempAttributes = CreateCertificateAttributes(DateTime.UtcNow.AddMinutes(-10), DateTime.UtcNow.AddMinutes(10)); var createKey = await _keyVaultClient.CreateCertificateAsync( _vaultBaseUrl, id, policySelfSignedNewKey, tempAttributes, null, ct) .ConfigureAwait(false); CertificateOperation operation; do { await Task.Delay(1000); operation = await _keyVaultClient.GetCertificateOperationAsync(_vaultBaseUrl, id, ct); } while (operation.Status == "inProgress" && !ct.IsCancellationRequested); if (operation.Status != "completed") { throw new ServiceResultException(StatusCodes.BadUnexpectedError, "Failed to create new key pair."); } var createdCertificateBundle = await _keyVaultClient.GetCertificateAsync(_vaultBaseUrl, id).ConfigureAwait(false); var caCertKeyIdentifier = createdCertificateBundle.KeyIdentifier.Identifier; caTempCertIdentifier = createdCertificateBundle.CertificateIdentifier.Identifier; // policy unknown issuer, reuse key var policyUnknownReuse = CreateCertificatePolicy(subject, keySize, false, true); var attributes = CreateCertificateAttributes(notBefore, notAfter); var tags = CreateCertificateTags(id, trusted); // create the CSR var createResult = await _keyVaultClient.CreateCertificateAsync( _vaultBaseUrl, id, policyUnknownReuse, attributes, tags, ct) .ConfigureAwait(false); if (createResult.Csr == null) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "Failed to read CSR from CreateCertificate."); } // decode the CSR and verify consistency var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(createResult.Csr); var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); if (createResult.Csr == null || pkcs10CertificationRequest == null || !pkcs10CertificationRequest.Verify()) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "Invalid CSR."); } // create the self signed root CA cert var publicKey = KeyVaultCertFactory.GetRSAPublicKey(info.SubjectPublicKeyInfo); var signedcert = await KeyVaultCertFactory.CreateSignedCertificate( null, null, subject, null, (ushort)keySize, notBefore, notAfter, (ushort)hashSize, null, publicKey, new KeyVaultSignatureGenerator(this, caCertKeyIdentifier, null), true, crlDistributionPoint); // merge Root CA cert with var mergeResult = await _keyVaultClient.MergeCertificateAsync( _vaultBaseUrl, id, new X509Certificate2Collection(signedcert) ); return(signedcert); } catch (KeyVaultErrorException kex) { var ex = kex; throw new ServiceResultException(StatusCodes.BadInternalError, "Failed to create new Root CA certificate"); } finally { if (caTempCertIdentifier != null) { try { // disable the temp cert for self signing operation var attr = new CertificateAttributes() { Enabled = false }; await _keyVaultClient.UpdateCertificateAsync(caTempCertIdentifier, null, attr); } catch { // intentionally ignore error } } } }
/// <summary> /// Creates a KeyVault signed certficate from signing request. /// </summary> public override async Task <X509Certificate2> SigningRequestAsync( ApplicationRecordDataType application, string[] domainNames, byte[] certificateRequest ) { try { var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest); if (!pkcs10CertificationRequest.Verify()) { throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR signature invalid."); } var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); var altNameExtension = GetAltNameExtensionFromCSRInfo(info); if (altNameExtension != null) { if (altNameExtension.Uris.Count > 0) { if (!altNameExtension.Uris.Contains(application.ApplicationUri)) { throw new ServiceResultException(StatusCodes.BadCertificateUriInvalid, "CSR AltNameExtension does not match " + application.ApplicationUri); } } if (altNameExtension.IPAddresses.Count > 0 || altNameExtension.DomainNames.Count > 0) { var domainNameList = new List <string>(); domainNameList.AddRange(altNameExtension.DomainNames); domainNameList.AddRange(altNameExtension.IPAddresses); domainNames = domainNameList.ToArray(); } } var authorityInformationAccess = BuildAuthorityInformationAccessUrl(); DateTime notBefore = DateTime.UtcNow.AddDays(-1); await LoadPublicAssets().ConfigureAwait(false); var signingCert = Certificate; { var publicKey = KeyVaultCertFactory.GetRSAPublicKey(info.SubjectPublicKeyInfo); return(await KeyVaultCertFactory.CreateSignedCertificate( application.ApplicationUri, application.ApplicationNames.Count > 0?application.ApplicationNames[0].Text : "ApplicationName", info.Subject.ToString(), domainNames, Configuration.DefaultCertificateKeySize, notBefore, notBefore.AddMonths(Configuration.DefaultCertificateLifetime), Configuration.DefaultCertificateHashSize, signingCert, publicKey, new KeyVaultSignatureGenerator(_keyVaultServiceClient, _caCertKeyIdentifier, signingCert), extensionUrl : authorityInformationAccess )); } } catch (Exception ex) { if (ex is ServiceResultException) { throw ex as ServiceResultException; } throw new ServiceResultException(StatusCodes.BadInvalidArgument, ex.Message); } }