创建C#SCEP服务器

时间:2016-09-15 11:24:34

标签: c# mdm scep

我正在尝试构建一个SCEP服务器以支持Apple MDM设备注册。这需要在我们当前的MDM服务中实现,用C#编写。

我已经研究了以下内容的灵感:

  1. JSCEP,一个用于scep服务器实现的https://github.com/jscep/jscep
  2. 的java库
  3. Bouncy Castle(复杂,而不是C#方面的大量文档)
  4. Cisco SCEP文档http://www.cisco.com/c/en/us/support/docs/security-vpn/public-key-infrastructure-pki/116167-technote-scep-00.html
  5. 有没有人知道有关创建C#SCEP服务器的任何可靠示例?我无法为此找到任何好的文档。

    更新

    这就是我现在所拥有的,它仍然无效,但我认为问题在于签名的pkcs7,但我不确定我错过了什么?

        public class ScepModule: NancyModule
    {
        /// <summary>
        /// The _log.
        /// </summary>
        private readonly ILog log = LogManager.GetLogger(typeof(ScepModule));
        /// <summary>
        /// Initializes a new instance of the <see cref="ScepModule"/> class.
        /// </summary>
        /// <param name="cp">
        /// The certificate provider.
        /// </param>
        /// <param name="config">
        /// The config.
        /// </param>
        public ScepModule(MdmConfigDTO config)
            : base("/cimdm/scep")
        {
            this.log.Debug(m => m("Instanciating scep Module."));
            this.Get["/"] = result =>
            {
                var message = Request.Query["message"];
                var operation = Request.Query["operation"];
                if (operation == "GetCACert")
                {
                    return RespondWithCACert();
                }
                else if (operation == "GetCACaps")
                {
                    return RespondWithCACaps();
                }
                return "";
            };
            this.Post["/"] = result =>
            {
                var message = Request.Query["message"];
                var operation = Request.Query["operation"];
    
                byte[] requestData = null;
    
                using (var binaryReader = new BinaryReader(Request.Body))
                {
                    requestData = binaryReader.ReadBytes((int)Request.Body.Length);
                }
    
                var headers = Request.Headers;
                foreach (var header in headers)
                {
                    this.log.Debug(m => m("Header: {0}, Value: {1}", header.Key, String.Join(",", header.Value)));
                }
    
                var caCert = getSignerCert();
    
                var signingCert = createSigningCert(caCert, requestData, config);
    
                return signingCert;
            };
            this.log.Debug(m => m("Finished Instanciating scep Module."));
        }
    
    
        private Response RespondWithCACert()
        {
            var caCert = getSignerCert();
    
            var response = new Response();
            response.ContentType = "application/x-x509-ca-cert";
            response.Contents = stream =>
            {
                byte[] data = caCert.Export(X509ContentType.Cert);
                stream.Write(data, 0, data.Length);
                stream.Flush();
                stream.Close();
            };
            return response;
        }
    
        private Response RespondWithCACaps()
        {
            var response = new Response();
            response.ContentType = "text/plain; charset=ISO-8859-1";
            //byte[] data = Encoding.UTF8.GetBytes("POSTPKIOperation\nSHA-512\nSHA-256\nSHA-1");
            byte[] data = Encoding.UTF8.GetBytes("POSTPKIOperation\nSHA-1");
    
            response.Contents = stream =>
            {
                stream.Write(data, 0, data.Length);
                stream.Flush();
                stream.Close();
            };
            return response;
        }
    
        private Response createSigningCert(X509Certificate2 caCert, byte[] data, MdmConfigDTO config)
        {
            var signedResponse = new SignedCms();
            signedResponse.Decode(data);
    
            var caChain = new X509Certificate2Collection(caCert);
    
            signedResponse.CheckSignature(caChain, true);
    
            var attributes = signedResponse
                .SignerInfos
                .Cast<System.Security.Cryptography.Pkcs.SignerInfo>()
                .SelectMany(si => si.SignedAttributes.Cast<CryptographicAttributeObject>());
    
            // Any errors then return null
            if (attributes.Any(att => att.Oid.Value.Equals(Oids.Scep.FailInfo)))
            {
                return null;
            }
    
            byte[] msg = DecryptMsg(signedResponse.ContentInfo.Content, caChain);
            byte[] certResult = GenerateSelfSignedClientCertificate(msg, caCert, config);
            X509Certificate2Collection reqCerts = signedResponse.Certificates;
    
            //Create Enveloped PKCS#7 data
            var envelpeDataPkcs7 = createEnvelopedDataPkcs7(certResult);
    
            //Create Signed PKCS#7 data
            var signedDataPkcs7 = createSignedDataPkcs7(envelpeDataPkcs7, caCert, attributes);
    
    
            var response = new Response();
            response.ContentType = "application/x-pki-message";
            response.WithHeader("Cache-Control", "no-store, no-cache, must-revalidate");
            response.WithHeader("Pragma", "no-cache");
    
            var execPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            File.WriteAllBytes(execPath + "\\signedDataPkcs7.p7b", signedDataPkcs7);
            File.WriteAllBytes(execPath + "\\envelpeDataPkcs7.p7b", envelpeDataPkcs7);
    
            response.Contents = stream =>
            {
                stream.Write(signedDataPkcs7, 0, signedDataPkcs7.Length);
                stream.Flush();
                stream.Close();
            };
            return response;
        }
    
        private byte[] GenerateSelfSignedClientCertificate(byte[] encodedPkcs10, X509Certificate2 caCert, MdmConfigDTO config)
        {
            var execPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            File.WriteAllText(execPath + "\\scepPkcs10.csr", "-----BEGIN CERTIFICATE REQUEST-----\n" + Convert.ToBase64String(encodedPkcs10) + "\n-----END CERTIFICATE REQUEST-----");
    
            Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest(encodedPkcs10);
    
            CertificationRequestInfo csrInfo = csr.GetCertificationRequestInfo();
            SubjectPublicKeyInfo pki = csrInfo.SubjectPublicKeyInfo;
    
            Asn1Set attributes = csrInfo.Attributes;
            //pub key for the signed cert
            var publicKey = pki.GetPublicKey();
    
            // Build a Version3 Certificate
            DateTime startDate = DateTime.UtcNow.AddMonths(-1);
            DateTime expiryDate = startDate.AddYears(10);
            BigInteger serialNumber = new BigInteger(32, new Random());
    
            this.log.Debug(m => m("Certificate Signing Request Subject is: {0}", csrInfo.Subject));
            CmsSignedDataGenerator cmsGen = new CmsSignedDataGenerator();
    
            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
            string signerCN = caCert.GetNameInfo(X509NameType.SimpleName, true);
    
            certGen.SetSubjectDN(new X509Name(String.Format("CN={0}", config.HostName)));
    
            certGen.SetSerialNumber(serialNumber);
            certGen.SetIssuerDN(new X509Name(String.Format("CN={0}", signerCN)));
            certGen.SetNotBefore(startDate);
            certGen.SetNotAfter(expiryDate);
            certGen.SetSignatureAlgorithm("SHA1withRSA");
            certGen.SetPublicKey(PublicKeyFactory.CreateKey(pki));
    
            AsymmetricCipherKeyPair caPair = DotNetUtilities.GetKeyPair(caCert.PrivateKey);
    
            for(int i=0; i!=attributes.Count; i++)
            {
                AttributeX509 attr = AttributeX509.GetInstance(attributes[i]);
    
                //process extension request
                if (attr.AttrType.Id.Equals(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest.Id))
                {
                    X509Extensions extensions = X509Extensions.GetInstance(attr.AttrValues[0]);
    
                    var e = extensions.ExtensionOids.GetEnumerator();
                    while (e.MoveNext())
                    {
                        DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
                        Org.BouncyCastle.Asn1.X509.X509Extension ext = extensions.GetExtension(oid);
    
                        certGen.AddExtension(oid, ext.IsCritical, ext.GetParsedValue());
                    }
                }
            }
    
            //certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment));
            certGen.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeID.AnyExtendedKeyUsage));
            certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(0));
    
            Org.BouncyCastle.X509.X509Certificate selfSignedCert = certGen.Generate(caPair.Private);
    
            //Check if the certificate can be verified
            selfSignedCert.Verify(caPair.Public);
    
            if (log.IsDebugEnabled)
            {
                //var execPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                File.WriteAllBytes(execPath + "\\scepCertificate.pfx", selfSignedCert.GetEncoded());
            }
    
             return selfSignedCert.GetEncoded();
        }
    
        private byte[] createEnvelopedDataPkcs7(byte[] pkcs7RequestData)
        {
            var recipient = new CmsRecipient(new X509Certificate2(pkcs7RequestData));
    
            var envelopedContent = new System.Security.Cryptography.Pkcs.ContentInfo(new Oid(Oids.Pkcs7.EncryptedData, "envelopedData"), pkcs7RequestData);
            //var envelopedContent = new System.Security.Cryptography.Pkcs.ContentInfo(pkcs7RequestData);
            var envelopedMessage = new EnvelopedCms(envelopedContent);
            //var envelopedMessage = new EnvelopedCms(Con);
    
            envelopedMessage.Encrypt(recipient);
            var encryptedMessageData = envelopedMessage.Encode();
    
            return encryptedMessageData;
        }
    
        private byte[] createSignedDataPkcs7(byte[] encryptedMessageData, X509Certificate2 localPrivateKey, IEnumerable<CryptographicAttributeObject> attributes)
        {
    
            var senderNonce = attributes
                .Single(att => att.Oid.Value.Equals(Oids.Scep.SenderNonce))
                .Values[0];
    
            var transactionId = attributes
                .Single(att => att.Oid.Value.Equals(Oids.Scep.TransactionId))
                .Values[0];
    
            // Create the outer envelope, signed with the local private key
            var signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, localPrivateKey);
            //{
            //    DigestAlgorithm = new Oid(Oids.Pkcs.SHA1, "digestAlorithm")
            //};
    
            //signer.SignedAttributes.Add(signingTime);
            var messageType = new AsnEncodedData(Oids.Scep.MessageType, DerEncoding.EncodePrintableString("3"));
            signer.SignedAttributes.Add(messageType);
            signer.SignedAttributes.Add(transactionId);
            var recipientNonce = new Pkcs9AttributeObject(Oids.Scep.RecipientNonce, DerEncoding.EncodeOctet(senderNonce.RawData));
            signer.SignedAttributes.Add(recipientNonce);
    
            var pkiStatus = new AsnEncodedData(Oids.Scep.PkiStatus, DerEncoding.EncodePrintableString("0"));
            signer.SignedAttributes.Add(pkiStatus);
    
            var nonceBytes = new byte[16];
            RNGCryptoServiceProvider.Create().GetBytes(nonceBytes);
            senderNonce = new Pkcs9AttributeObject(Oids.Scep.SenderNonce, DerEncoding.EncodeOctet(nonceBytes));
            signer.SignedAttributes.Add(senderNonce);
    
    
            //var failInfo = new Pkcs9AttributeObject(Oids.Scep.FailInfo, DerEncoding.EncodePrintableString("2"));
            //signer.SignedAttributes.Add(failInfo);
    
            // Seems that the oid is not needed for this envelope
            var contentInfo = new System.Security.Cryptography.Pkcs.ContentInfo(encryptedMessageData); //new Oid("1.2.840.113549.1.7.1", "data"), encryptedMessageData);
            var signedCms = new SignedCms(contentInfo, false);
            signedCms.ComputeSignature(signer);
    
            return signedCms.Encode();
        }
    
        private X509Certificate2 getSignerCert()
        {
            string thumbprint = "CACertThumbprint";
    
            thumbprint = Regex.Replace(thumbprint, @"[^\da-zA-z]", string.Empty).ToUpper();
    
            // Get a local private key for sigining the outer envelope 
            var certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
            certStore.Open(OpenFlags.ReadOnly);
    
            var signerCert = certStore
                .Certificates
                .Find(X509FindType.FindByThumbprint, thumbprint, false)
                .Cast<X509Certificate2>()
                .Single();
    
            certStore.Close();
            return signerCert;
        }
    
        //  Decrypt the encoded EnvelopedCms message for one of the
        //  recipients.
        public Byte[] DecryptMsg(byte[] encodedEnvelopedCms, X509Certificate2Collection caChain)
        {
            //  Prepare object in which to decode and decrypt.
            EnvelopedCms envelopedCms = new EnvelopedCms();
    
            //  Decode the message.
            envelopedCms.Decode(encodedEnvelopedCms);
    
            //  Display the number of recipients
            DisplayEnvelopedCms(envelopedCms, false);
    
            //  Decrypt the message.
            this.log.Debug("Decrypting Data for one recipient ... ");
            envelopedCms.Decrypt(envelopedCms.RecipientInfos[0], caChain);
            this.log.Debug("Done.");
    
            //  The decrypted message occupies the ContentInfo property
            //  after the Decrypt method is invoked.
            return envelopedCms.ContentInfo.Content;
        }
    
        //  Display the ContentInfo property of an EnvelopedCms object.
        private void DisplayEnvelopedCmsContent(String desc,
            EnvelopedCms envelopedCms)
        {
            this.log.Debug(string.Format(desc + " (length {0}):  ",
                envelopedCms.ContentInfo.Content.Length));
            foreach (byte b in envelopedCms.ContentInfo.Content)
            {
                this.log.Debug(b.ToString() + " ");
            }
        }
    
        //  Display some properties of an EnvelopedCms object.
        private void DisplayEnvelopedCms(EnvelopedCms e,
            Boolean displayContent)
        {
            this.log.Debug("\nEnveloped PKCS #7 Message Information:");
            this.log.Debug(string.Format(
                "\tThe number of recipients for the Enveloped PKCS #7 " +
                "is:  {0}", e.RecipientInfos.Count));
            for (int i = 0; i < e.RecipientInfos.Count; i++)
            {
                this.log.Debug(string.Format(
                    "\tRecipient #{0} has type {1}.",
                    i + 1,
                    e.RecipientInfos[i].RecipientIdentifier.Type));
            }
            if (displayContent)
            {
                DisplayEnvelopedCmsContent("Enveloped PKCS #7 Content", e);
            }
    
        }
    }
    

0 个答案:

没有答案