المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : Certificate Management / SslStream encryption



C# Programming
04-28-2009, 12:00 PM
Hi,

I am currently developing a client/server application which consists of a "root/master" server, some "normal" servers and some clients.
I want the "root/master" server and the "normal" servers to be securely identified and i want to encrypt traffic between "root/master" server,
"normal" server and clients using Ssl encryption.

Minimum system requirements for servers should be win server 2003 and for clients winXP. (Currently I use win server 2008 for "root/master" server as I got the certificate management working only with the new Certificate Enrollment API)

That's why I need:

- One certificate for the "root/master" server
- One certificate for each "normal" server
- One certificate for each client

-> The certificates of the "root/master" server and the "normal" servers have to be signed by a CA so that I can verify the identity of the servers.
-> The "root/master" server should serve as CA.

This is what I did:

- Create certificate for "root/master" server manually on windows server 2008.
- Imported this certificate manually on the "normal" servers and clients computers.

The "normal" servers and clients can now connect to the "root/master" server using SslStream and identify it.

------------------------------------------------------------------

To get the certificates for the "normal" servers I wanted them to send a certificate request to the "root/master" server.
Then the "root/master" server issues the request and sends certificate back.

I don't want the "normal" server admin to do that. It should automatically be done by the "normal" server when first connecting to the
"root/master" server.

This is what I did:

"Normal" server
...connects to "root/master" server using sslstream and identifies "root/master" server
...sends CommonName for certificate creation

"Root/Master" server (using Certificate Enrollment API)
...creates certificate request
...sends certificate request
...issues certificate request
...get issued certificate and sends it back to "normal" server

Next connection

"Normal" server
...uses issued certificate to "authenticate as client"
-> Problem:
-> The "normal" server does not found the private key for the issued certificate.
-> I looked at the certificate and it has no private key attached. So something went wrong during the certification creation on the "root/master" server.

Has somebody an idea what went wrong during certificate creation?
Is there a general "error" in the process which I designed to let the "normal" servers get their certificates?

------------------------------------------------------------------

Code:

"normal" server


byte[] cert = this.ReadBytes();
CertManager.CreateCert(cert);

X509Certificate certClient = new X509Certificate2(@"C:\newcert.cer");



"root/master" Server handling

String certRequest = CertManagerVista.CreateRequest("CoordClient11");
CertRequest requestObj = CertManagerVista.SendRequest(certRequest);
CertManagerVista.Issue(requestObj);
String cert = CertManagerVista.GetRequestStatus(requestObj);

// cert to bytes
char[] chars = cert.ToCharArray();
int count = chars.Length;
byte[] bytes = new byte[count];
for (int i = 0; i < count; i++)
{
bytes[i] = BitConverter.GetBytes(chars[i])[0];
}

// Send cert
this.SendBytes(bytes);


CertManagerVista.cs

static public String CreateRequest(String cn)
{
// Create all the objects that will be required
CX509CertificateRequestPkcs10 objPkcs10 = new CX509CertificateRequestPkcs10Class();
CX509PrivateKey objPrivateKey = new CX509PrivateKeyClass();
CCspInformation objCSP = new CCspInformationClass();
CCspInformations objCSPs = new CCspInformationsClass();
CX500DistinguishedName objDN = new CX500DistinguishedNameClass();
CX509Enrollment objEnroll = new CX509EnrollmentClass();
CObjectIds objObjectIds = new CObjectIdsClass();
CObjectId objObjectId = new CObjectIdClass();
CX509ExtensionKeyUsage objExtensionKeyUsage = new CX509ExtensionKeyUsageClass();
CX509ExtensionEnhancedKeyUsage objX509ExtensionEnhancedKeyUsage = new CX509ExtensionEnhancedKeyUsageClass();
String strRequest = "";
privateKey = "";

try
{
// Initialize the csp object using the desired Cryptograhic Service Provider (CSP)
objCSP.InitializeFromName(
"Microsoft Enhanced Cryptographic Provider v1.0"
);

// Add this CSP object to the CSP collection object
objCSPs.Add(objCSP);

// Provide key container name, key length and key spec to the private key object
//objPrivateKey.ContainerName = "AlejaCMa";
objPrivateKey.Length = 1024;
objPrivateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE;
objPrivateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
objPrivateKey.MachineContext = false;

// Provide the CSP collection object (in this case containing only 1 CSP object)
// to the private key object
objPrivateKey.CspInformations = objCSPs;

// Create the actual key pair
objPrivateKey.Create();
//privateKey = objPrivateKey.Export("PRIVATEBLOB", EncodingType.XCN_CRYPT_STRING_BASE64); // did not work

// 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
objPkcs10.InitializeFromPrivateKey(
X509CertificateEnrollmentContext.ContextUser,
objPrivateKey,
""
);


// Key Usage Extension
objExtensionKeyUsage.InitializeEncode(
X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE |
X509KeyUsageFlags.XCN_CERT_NON_REPUDIATION_KEY_USAGE |
X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE |
X509KeyUsageFlags.XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE
);
objPkcs10.X509Extensions.Add((CX509Extension)objExtensionKeyUsage);

// Enhanced Key Usage Extension
objObjectId.InitializeFromValue("1.3.6.1.5.5.7.3.2"); // OID for Client Authentication usage
objObjectIds.Add(objObjectId);
objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
objPkcs10.X509Extensions.Add((CX509Extension)objX509ExtensionEnhancedKeyUsage);

// Encode the name in using the Distinguished Name object
objDN.Encode(
"CN=" + cn,
X500NameFlags.XCN_CERT_NAME_STR_NONE
);

// Assing the subject name by using the Distinguished Name object initialized above
objPkcs10.Subject = objDN;

// Create enrollment request
objEnroll.InitializeFromRequest(objPkcs10);
strRequest = objEnroll.CreateRequest(
EncodingType.XCN_CRYPT_STRING_BASE64
);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return strRequest;
}

static public CertRequest SendRequest(String request)
{
// Create all the objects that will be required
CCertConfig objCertConfig = new CCertConfigClass();
CCertRequest objCertRequest = new CCertRequestClass();
string strCAConfig;
string strRequest;
int iDisposition;
string strDisposition;

try
{
strRequest = request;

// Get CA config from UI
strCAConfig = objCertConfig.GetConfig(CC_DEFAULTCONFIG);
//strCAConfig = objCertConfig.GetConfig(CC_UIPICKCONFIG);

// Submit the request
iDisposition = objCertRequest.Submit(
CR_IN_BASE64 | CR_IN_FORMATANY,
strRequest,
null,
strCAConfig
);

// Check the submission status
if (CR_DISP_ISSUED != iDisposition) // Not enrolled
{
strDisposition = objCertRequest.GetDispositionMessage();

if (CR_DISP_UNDER_SUBMISSION == iDisposition) // Pending
{
Console.WriteLine("The submission is pending: " + strDisposition);
return new CertRequest(objCertRequest);
}
else // Failed
{
Console.WriteLine("The submission failed: " + strDisposition);
Console.WriteLine("Last status: " + objCertRequest.GetLastStatus().ToString());
return new CertRequest(objCertRequest);
}
}

//// Get the certificate
//strCert = objCertRequest.GetCertificate(
// CR_OUT_BASE64 | CR_OUT_CHAIN
//);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return new CertRequest(objCertRequest);
}

static public String GetRequestStatus(CertRequest certRequest)
{
CCertRequest objCertRequest = certRequest.request;

CCertConfig objCertConfig = new CCertConfigClass();
String strCAConfig = objCertConfig.GetConfig(CC_DEFAULTCONFIG);
// ******* the request, since is has now the 'Issued' status
int numDisposition = objCertRequest.RetrievePending(objCertRequest.GetRequestId(), strCAConfig); // Replaced strConfig with ""


// Get the certificate
String certStr = objCertRequest.GetCertificate(CR_OUT_BASE64HEADER);

return certStr;
}

static public void Issue(CertRequest request)
{
CCertAdmin objAdmin = new CCertAdminClass();
CCertConfig objCertConfig = new CCertConfigClass();
String strCAConfig = objCertConfig.GetConfig(CC_DEFAULTCONFIG);

int requestId = request.request.GetRequestId();

// Now issue the request
int numDisposition = objAdmin.ResubmitRequest(strCAConfig, requestId);
}

static public void AcceptPKCS7(String cert)
{
// Create all the objects that will be required
CX509Enrollment objEnroll = new CX509EnrollmentClass();
string strCert;

try
{
strCert = cert;

// Install the certificate
objEnroll.Initialize(X509CertificateEnrollmentContext.ContextUser);
objEnroll.InstallResponse(
InstallResponseRestrictionFlags.AllowUntrustedRoot,
strCert,
EncodingType.XCN_CRYPT_STRING_BASE64,
null
);

Console.WriteLine("Certificate installed!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}


CertManager.cs

static public void CreateCert(byte[] data)
{
X509Certificate2 c = new X509Certificate2(data);
FileStream fs = new FileStream(@"C:\newcert.cer", FileMode.Create);
fs.Write(data, 0, data.Length);
fs.Close();
}