src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/TestHost.cs (225 lines of code) (raw):

// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.IO; using System.Net; using System.Security.Cryptography.X509Certificates; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; namespace WcfService { [ServiceContract] public interface ITestHost { [OperationContract] [WebGet(UriTemplate = "ClientCert?asPem={asPem}", BodyStyle = WebMessageBodyStyle.Bare)] Stream ClientCert(bool asPem); [OperationContract] [WebGet(UriTemplate = "Crl", BodyStyle = WebMessageBodyStyle.Bare)] Stream Crl(); [OperationContract] [WebGet(UriTemplate = "PeerCert?asPem={asPem}", BodyStyle = WebMessageBodyStyle.Bare)] Stream PeerCert(bool asPem); [OperationContract] [WebGet(UriTemplate = "MachineCert?asPem={asPem}", BodyStyle = WebMessageBodyStyle.Bare)] Stream MachineCert(bool asPem); [OperationContract] [WebGet(UriTemplate = "RootCert?asPem={asPem}", BodyStyle = WebMessageBodyStyle.Bare)] Stream RootCert(bool asPem); [OperationContract] [WebGet(UriTemplate = "Fqdn", BodyStyle = WebMessageBodyStyle.Bare)] Stream Fqdn(); [OperationContract] [WebGet(UriTemplate = "Ping", BodyStyle = WebMessageBodyStyle.Bare)] Stream Ping(); [OperationContract] [WebGet(UriTemplate = "State", BodyStyle = WebMessageBodyStyle.Bare)] Stream State(); } public class TestHost : ITestHost { public Stream ClientCert(bool asPem) { X509Certificate2 clientCert = CertificateFromSubject(StoreName.My, StoreLocation.LocalMachine, "WCF Client Certificate"); byte[] response; if (clientCert == null) { WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError; response = Encoding.UTF8.GetBytes("Client certificate not found on system"); } else { if (asPem) { WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"wcf-client-cert.crt\""; WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-pem-file"; response = Encoding.ASCII.GetBytes(GetCertificateAsPem(clientCert)); } else { WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"wcf-client-cert.pfx\""; WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-pkcs12"; response = clientCert.Export(X509ContentType.Pfx, "test"); } } return new MemoryStream(response); } public Stream Crl() { // The test.crl is generated by the cert util tool and will not expire until the root cert expires. // We should investigate if we can generate it in the run time. This is not a blocking issue. string downloadFilePath = @"c:\\WCFTest\\test.crl"; WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-pkcs7-crl"; WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"wcf-crl.crl\""; return File.OpenRead(downloadFilePath); } public Stream RootCert(bool asPem) { X509Certificate2 rootCert = CertificateFromSubject(StoreName.Root, StoreLocation.LocalMachine, "DO_NOT_TRUST_WcfBridgeRootCA"); byte[] response; if (rootCert == null) { WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError; response = Encoding.UTF8.GetBytes("Root certificate not found on system"); } else { WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"wcf-root-cert.crt\""; if (asPem) { WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-pem-file"; response = Encoding.ASCII.GetBytes(GetCertificateAsPem(rootCert)); } else { WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-x509-ca-cert"; response = rootCert.RawData; } } return new MemoryStream(response); } public Stream Fqdn() { return new MemoryStream(Encoding.UTF8.GetBytes(Dns.GetHostEntry("127.0.0.1").HostName)); } public Stream PeerCert(bool asPem) { X509Certificate2 peerCert = CertificateFromFriendlyName(StoreName.TrustedPeople, StoreLocation.LocalMachine, "WCF Bridge - UserPeerTrustCertificateResource"); byte[] response; if (peerCert == null) { WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError; response = Encoding.UTF8.GetBytes("Peer certificate not found on system"); } else { if (asPem) { WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"wcf-peer-cert.crt\""; WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-pem-file"; response = Encoding.ASCII.GetBytes(GetCertificateAsPem(peerCert)); } else { WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"wcf-peer-cert.pfx\""; WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-pkcs12"; response = peerCert.Export(X509ContentType.Pfx, "test"); } } return new MemoryStream(response); } public Stream MachineCert(bool asPem) { X509Certificate2 machineCert = CertificateFromFriendlyName(StoreName.My, StoreLocation.LocalMachine, "WCF Bridge - Machine certificate generated by the CertificateManager"); byte[] response; if (machineCert == null) { WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError; response = Encoding.UTF8.GetBytes("Machine certificate not found on system"); } else { WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"wcf-machine-cert.crt\""; if (asPem) { WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-pem-file"; response = Encoding.ASCII.GetBytes(GetCertificateAsPem(machineCert)); } else { WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-x509-user-cert"; response = machineCert.RawData; } } return new MemoryStream(response); } public Stream Ping() { return new MemoryStream(Encoding.UTF8.GetBytes("Service has started")); } public Stream State() { return new MemoryStream(); } // All certificates have installed on the server machine, including client cert by the cert util tool. public static X509Certificate2 CertificateFromSubject(StoreName name, StoreLocation location, string subjectName) { X509Store store = null; try { store = new X509Store(name, location); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection foundCertificates = store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, validOnly: true); return foundCertificates.Count == 0 ? null : foundCertificates[0]; } finally { if (store != null) { store.Close(); } } } public static X509Certificate2 CertificateFromFriendlyName(StoreName name, StoreLocation location, string friendlyName) { X509Store store = null; try { store = new X509Store(name, location); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection foundCertificates = store.Certificates.Find(X509FindType.FindByIssuerName, "DO_NOT_TRUST_WcfBridgeRootCA", false); foreach (X509Certificate2 cert in foundCertificates) { if (cert.FriendlyName == friendlyName) { return cert; } } return null; } finally { if (store != null) { store.Close(); } } } public static string GetCertificateAsPem(X509Certificate2 certificate) { string base64String = Convert.ToBase64String(certificate.RawData); const string header = "-----BEGIN CERTIFICATE-----\n"; const string footer = "-----END CERTIFICATE-----"; StringBuilder builder = new StringBuilder(base64String.Length + header.Length + footer.Length); int base64StringIndex = 0; builder.Append(header); while (base64StringIndex < base64String.Length) { int charactersToAppend = Math.Min(64, base64String.Length - base64StringIndex); builder.Append(base64String, base64StringIndex, charactersToAppend); // PEM dictates that this must be a \n, not OS-dependent builder.Append('\n'); base64StringIndex += charactersToAppend; } builder.Append(footer); return builder.ToString(); } } }