성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>닷넷(C#) 코드로 인증서 요청 코드 만드는 방법</h1> <p> 인터넷 떠돌다가 본 코드인데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to create a certificate request with CertEnroll and .NET (C#) ; <a target='tab' href='https://learn.microsoft.com/en-us/archive/blogs/alejacma/how-to-create-a-certificate-request-with-certenroll-and-net-c'>https://learn.microsoft.com/en-us/archive/blogs/alejacma/how-to-create-a-certificate-request-with-certenroll-and-net-c</a> Cipher selection for sslStream in .NET 4.5 ; <a target='tab' href='http://stackoverflow.com/questions/22825663/cipher-selection-for-sslstream-in-net-4-5'>http://stackoverflow.com/questions/22825663/cipher-selection-for-sslstream-in-net-4-5</a> </pre> <br /> 저도 실습해봤습니다. ^^ C# 프로젝트를 하나 만들고 "CertEnroll 1.0 Type Library" 참조 추가를 한 다음 위의 코드를 거의 그대로 베끼면 됩니다.<br /> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using CERTENROLLLib; using System.Security.Cryptography.X509Certificates; namespace ConsoleApp1 { class Program { public static string GenerateRequest(string Subject, StoreLocation Location, string providerName, int KeyLength) { //code originally came from: http://blogs.msdn.com/b/alejacma/archive/2008/09/05/how-to-create-a-certificate-request-with-certenroll-and-net-c.aspx //modified version of it is here: http://stackoverflow.com/questions/16755634/issue-generating-a-csr-in-windows-vista-cx509certificaterequestpkcs10 //here is the standard for certificates: http://www.ietf.org/rfc/rfc3280.txt //the PKCS#10 certificate request (https://learn.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509certificaterequestpkcs10) CX509CertificateRequestPkcs10 objPkcs10 = new CX509CertificateRequestPkcs10(); //assymetric private key that can be used for encryption (https://learn.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509privatekey) CX509PrivateKey objPrivateKey = new CX509PrivateKey(); //access to the general information about a cryptographic provider (https://learn.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-icspinformation) CCspInformation objCSP = new CCspInformation(); //collection on cryptographic providers available: https://learn.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-icspinformation CCspInformations objCSPs = new CCspInformations(); CX500DistinguishedName objDN = new CX500DistinguishedName(); //top level object that enables installing a certificate response https://learn.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509enrollment CX509Enrollment objEnroll = new CX509Enrollment(); CObjectIds objObjectIds = new CObjectIds(); CObjectId objObjectId = new CObjectId(); CObjectId objObjectId2 = new CObjectId(); CX509ExtensionKeyUsage objExtensionKeyUsage = new CX509ExtensionKeyUsage(); CX509ExtensionEnhancedKeyUsage objX509ExtensionEnhancedKeyUsage = new CX509ExtensionEnhancedKeyUsage(); string csr_pem = null; // Initialize the csp object using the desired Cryptograhic Service Provider (CSP) objCSPs.AddAvailableCsps(); //Provide key container name, key length and key spec to the private key object objPrivateKey.ProviderName = providerName; objPrivateKey.Length = KeyLength; objPrivateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE; //Must flag as XCN_AT_KEYEXCHANGE to use this certificate for exchanging symmetric keys (needed for most SSL cipher suites) objPrivateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES; if (Location == StoreLocation.LocalMachine) objPrivateKey.MachineContext = true; else objPrivateKey.MachineContext = false; //must set this to true if installing to the local machine certificate store objPrivateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG; //must set this if we want to be able to export it later. objPrivateKey.CspInformations = objCSPs; // Create the actual key pair objPrivateKey.Create(); // Initialize the PKCS#10 certificate request object based on the private key. // Using the context, indicate that this is a user certificate request and don't // provide a template name if (Location == StoreLocation.LocalMachine) objPkcs10.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, objPrivateKey, ""); else objPkcs10.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextUser, objPrivateKey, ""); //Set hash to sha256 CObjectId hashobj = new CObjectId(); hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "SHA256"); objPkcs10.HashAlgorithm = hashobj; // Key Usage Extension -- we only need digital signature and key encipherment for TLS: // NOTE: in openSSL, I didn't used to request any specific extensions. Instead, I let the CA add them objExtensionKeyUsage.InitializeEncode( CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE ); objPkcs10.X509Extensions.Add((CX509Extension)objExtensionKeyUsage); // Enhanced Key Usage Extension objObjectId.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // OID for Server Authentication usage (see this: http://stackoverflow.com/questions/17477279/client-authentication-1-3-6-1-5-5-7-3-2-oid-in-server-certificates) objObjectId2.InitializeFromValue("1.3.6.1.5.5.7.3.2"); // OID for Client Authentication usage (see this: http://stackoverflow.com/questions/17477279/client-authentication-1-3-6-1-5-5-7-3-2-oid-in-server-certificates) objObjectIds.Add(objObjectId); objObjectIds.Add(objObjectId2); objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds); objPkcs10.X509Extensions.Add((CX509Extension)objX509ExtensionEnhancedKeyUsage); // Encode the name in using the Distinguished Name object // see here: http://https://learn.microsoft.com/en-us/windows/win32/api/certenroll/ne-certenroll-x500nameflags objDN.Encode(Subject, X500NameFlags.XCN_CERT_NAME_STR_SEMICOLON_FLAG); // Assign the subject name by using the Distinguished Name object initialized above objPkcs10.Subject = objDN; //suppress extra attributes: objPkcs10.SuppressDefaults = true; // Create enrollment request // objEnroll.InitializeFromTemplateName(X509CertificateEnrollmentContext.ContextMachine, "WebServer"); objEnroll.InitializeFromRequest(objPkcs10); csr_pem = objEnroll.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64); csr_pem = "-----BEGIN CERTIFICATE REQUEST-----\r\n" + csr_pem + "-----END CERTIFICATE REQUEST-----"; return csr_pem; } } } </pre> <br /> 사용을 위한 호출은 이렇게 간단합니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static void Main(string[] args) { string txt = GenerateRequest(<span style='color: blue; font-weight: bold'>"CN=the10"</span>, StoreLocation.CurrentUser, "Microsoft RSA SChannel Cryptographic Provider", 1024); Console.WriteLine(txt); } </pre> <br /> 출력된 txt 내용은 이렇게 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > -----BEGIN CERTIFICATE REQUEST----- MIIBjzCB+QIBADAQMQ4wDAYDVQQDDAV0aGUxMDCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEAtotimc9N0i6VaWxbgktp28KxbX7xlr3QXFhosqGh2Rqs5fP032HZ CZ920PciQSijof8GbLL/sVMImPD8ACfoWzfeP8HDoC6YaXD2CtibxvdoXAEkFrfE RtfG/gxCyEc6O7zDDIyPygPG+R8ih3I2HflzxQmNg1kJ/bzKgLz+b10CAwEAAaBA MD4GCSqGSIb3DQEJDjExMC8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQAMOHR9g9rpDeDt8a+Y gNGsJ0G3JGs9bEFwY6m8mMHiRDBlIueIBnn7PF9+CIeV2xVGgPMtyDL3wYnrjgjM WEO2OXpuNNl2m1B14oBYBT+5Bqo06S5rckzMGmrPArUOw94zdnvcp22h3RH86rTA MmhAarv9DL3tVIiP/Ofh9xOv1Q== -----END CERTIFICATE REQUEST----- </pre> <br /> 그러니까 위의 코드는 결국 다음의 글에서 설명한,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 2. 웹 사이트에 SSL 을 적용 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/372'>http://www.sysnet.pe.kr/2/0/372</a> </pre> <br /> 1번 단계인 "IIS 관리자에서 인증서 서비스로 보낼 '요청 파일' 준비"를 한 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 실제로 위의 코드가 생산한 CSR 내용으로 인증서를 발급받아 볼까요? ^^ 정식 인증서 업체로는 곤란하니, Windows 서버에 인증서 서비스를 설치한 다음 CA 관리 콘솔을 띄웁니다.<br /> <br /> 다음 그림에서 보는 것처럼,<br /> <br /> <img alt='create_csr_1.png' src='/SysWebRes/bbs/create_csr_1.png' /><br /> <br /> CA 서버 명 노드를 마우스 우 클릭해 "All Tasks" / "Submit new request..." 메뉴를 선택하면 파일 선택 대화창이 뜹니다. 그럼, 위의 "-----BEGIN CERTIFICATE REQUEST----- ... -----END CERTIFICATE REQUEST-----" 내용을 파일로 저장한 것을 선택해 줍니다.<br /> <br /> 선택하자마자, CA 서비스는 해당 인증서 요청을 "Pending Requests"에 보관합니다.<br /> <br /> <img alt='create_csr_2.png' src='/SysWebRes/bbs/create_csr_2.png' /><br /> <br /> 그럼, 위의 인증서에 마우스 우 클릭하고 "All Tasks" / "Issue" 메뉴를 눌러 명시적인 발급을 하면 곧바로 "Pending Requests"에는 사라지고 "Issued Certificates" 영역으로 이동합니다.<br /> <br /> 결국 다음과 같은 인증서를 확인할 수 있습니다. ^^<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='create_csr_3.png' src='/SysWebRes/bbs/create_csr_3.png' /><br /> <br /> 정말 잘 되는군요. ^^<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1115&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, Active Directory가 설치된 Enterprise CA 서비스에 이 글의 CSR 내용을 전달하면 다음과 같은 오류를 만나게 됩니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> The request contains no certificate template information. 0x80094801 (-2146875391 CERTSRV_E_NO_CERT_TYPE)<br /> Denied by Policy Module 0x80094801, The request does not contain a certificate template extension or the CertificateTemplate request attribute.<br /> </div><br /> <br /> 원인은 이렇고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > You may receive a "The request contains no certificate template information" error message when you submit a CSR to an enterprise CA by using the Certification Authority Microsoft Management Console (MMC) snap-in in Windows Server 2003 ; <a target='tab' href='https://support.microsoft.com/KB/910249'>https://support.microsoft.com/en-us/help/910249/you-may-receive-a-the-request-contains-no-certificate-template-information-error-message-when-you-submit-a-csr-to-an-enterprise-ca-by-using-the-certification-authority-microsoft-management-console-mmc-snap-in-in-windows-server-2003</a> </pre> <br /> 따라서, 인증서 템플릿을 반드시 지정해야 합니다.<br /> <br /> 방법을 찾아보니, CX509Enrollment 객체에 <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509enrollment-initializefromtemplatename'>InitializeFromTemplateName</a> 메서드가 제공되는데요. 아마도 "objEnroll.InitializeFromRequest(objPkcs10);" 호출 대신 "objEnroll.InitializeFromTemplateName(X509CertificateEnrollmentContext.ContextMachine, "WebServer");"라는 식으로 호출해야 할 듯!<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
7379
(왼쪽의 숫자를 입력해야 합니다.)