Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/05/28/certenrollcx509enrollmentp_createrequest-returns-error-0x80070057/
Post name: CertEnroll::CX509Enrollment::p_CreateRequest returns error 0x80070057
Original author: Alejandro Campos Magencio
Posting date: 2009-05-28T05:22:00+00:00


Hi all,

One of the issues we may find when trying the code in my post How to create a certificate request that uses key archival with CertEnroll (JavaScript)is the following error when creating the request:

CertEnroll::CX509Enrollment::p_CreateRequest: The parameter is incorrect. 0x80070057 (WIN32: 87)

In my case I was getting this error because I was not using the right certificate asKeyArchivalCertificate property of the CMC request. When I first tried the code I set that property to the Key Recovery Agent Certificate that I had configured in my CA, and I got the error. No, that is not the certificate we have to use. We have to set that property to the Exchange Certificate of the CA itself.

Additionally, the Subject Name of the certificate has to match Issuer Name + "-Xchg". For example, if cert issuer is "MyCAServer", the expected subject name is "MyCAServer-Xchg". The subject name of our Key Recovery Agent Certificate won't match that, but the Exchange cert of our CA will.

We can export the Exchange Certificate of a MS CA with the following command:

certutil -cainfo xchg > xchg.cer

And then we can use the Base64 text of that .cer file in our code.

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/05/28/certenrollcx509enrollmentp_installresponse-returns-error-0x80095002/
Post name: CertEnroll::CX509Enrollment::p_InstallResponse returns error 0x80095002
Original author: Alejandro Campos Magencio
Posting date: 2009-05-28T04:46:00+00:00


Hi all,

One of the issues we may find when trying the code in my post How to create a certificate request that uses key archival with CertEnroll (JavaScript)is the following:

Imagine we could finally create a request successfully. We sent it to the CA and then we tried to install its response (the .ceror the.p7b files that we got from the CA)with i.e.the code in How to create a certificate request with CertEnroll (ASP).But we gotthe following error:

CertEnroll::CX509Enrollment::p_InstallResponse: The key archival hash attribute was not found in the response. 0x80095002 (-2146873342)

We assume that the code we used to create the request works fine, because the CA accepts the request, it enrolls the certificate and give us the response, and we can see the key is archived in the CA. So the issue may have to do with the response of the CA that we try to install. What's going on then?

Well, the issue in my case was that I was getting the response with the Certificate Services web pages of my Microsoft CA, and those pagescan only return as a response the issued raw certificate (.cer file) or a pkcs7 package including it (.p7b file). But neither of them contains the Full Response of the CA. This is required for key archival because the full response is a pkcs7 signed by the CA with CMC content. The CMC content contains an attribute that the client uses to verify the CA received the correct encrypted private key in the request (prevents man-in-the-middle key stealing attacks).

Summing up, .cer or .p7b files won't suffice for key archival enrollment.

So I used certreq.exe tool to send the request to my CA and get the full response from it:

certreq -submit -attrib "CertificateTemplate:ArchiveUser" keyarchival.req keyarchival.cer keyarchival.p7b keyarchival.rsp

Note: ArchiveUser is the certificate template where I enabled key archival on my CA.

Then I took keyarchival.rsp and passed it to my sample and it worked just fine. I could install the response successfully.

More info on certreq.exe here: Appendix A: Certificate Request Structureand here: Appendix 3: Certreq.exe Syntax.

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/05/27/how-to-create-a-certificate-request-that-uses-key-archival-with-certenroll-javascript/
Post name: How to create a certificate request that uses key archival with CertEnroll (JavaScript)
Original author: Alejandro Campos Magencio
Posting date: 2009-05-27T11:42:00+00:00


Hi all,


If you want to request certificates to a CA and make use of Key Archival feature, first you need to prepare the environment to enable this feature on your CA: Certificate Services example implementation: Key archival and recoveryor Implementing Key Archival Walkthroughwill be of assistance here.


After that you could use a code like the following sampleto make the request with CertEnroll (based on How to create a certificate request with CertEnroll (JavaScript) sample):

<html>
<head>
<title>Certificate Request test</title>
</head>
<body>
<object id="objCertEnrollClassFactory" classid="clsid:884e2049-217d-11da-b2a4-000e7bbb2b09"></object>
<script language="javascript">

function CreateRequest()
{
document.write("<br>Create Request...");

try {
// Variables
var objCSP = objCertEnrollClassFactory.CreateObject("X509Enrollment.CCspInformation");
var objCSPs = objCertEnrollClassFactory.CreateObject("X509Enrollment.CCspInformations");
var objPrivateKey = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509PrivateKey");
var objRequest = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509CertificateRequestPkcs10");
var objCmcRequest = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509CertificateRequestCmc");
var objObjectIds = objCertEnrollClassFactory.CreateObject("X509Enrollment.CObjectIds");
var objObjectId = objCertEnrollClassFactory.CreateObject("X509Enrollment.CObjectId");
var objX509ExtensionEnhancedKeyUsage = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509ExtensionEnhancedKeyUsage");
var objExtensionTemplate = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509ExtensionTemplateName");
var objDn = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX500DistinguishedName");
var objEnroll = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509Enrollment");

// 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 = 1; // AT_KEYEXCHANGE = 1
//objPrivateKey.ExportPolicy = 0; // XCN_NCRYPT_ALLOW_EXPORT_NONE = 0

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

// Initialize P10 based on private key
objRequest.InitializeFromPrivateKey(1, objPrivateKey, ""); // context user = 1

// 1.3.6.1.5.5.7.3.2 Oid - Extension
objObjectId.InitializeFromValue("1.3.6.1.5.5.7.3.2");
objObjectIds.Add(objObjectId);
objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
objRequest.X509Extensions.Add(objX509ExtensionEnhancedKeyUsage);

// 1.3.6.1.5.5.7.3.3 Oid - Extension
//objExtensionTemplate.InitializeEncode("1.3.6.1.5.5.7.3.3");
//objRequest.X509Extensions.Add(objExtensionTemplate);

// DN related stuff
objDn.Encode("CN=alejacma", 0); // XCN_CERT_NAME_STR_NONE = 0
objRequest.Subject = objDn;

// Enroll
objCmcRequest.InitializeFromInnerRequest(objRequest);
objCmcRequest.KeyArchivalCertificate =
"MIIFxDCCBKygAwIBAgIKG2cmPwAAAAAADDANBgkqhkiG9w0BAQUFADBJMRMwEQYK" +
...
"9Hwz0oPmQfi3VEXw16eBHf6EpmyOC8nBFeYPv9FKfuVHB9W3JNh+ZA=="

objEnroll.InitializeFromRequest(objCmcRequest);
var pkcs10 = objEnroll.CreateRequest(3); // XCN_CRYPT_STRING_BASE64REQUESTHEADER = 3

document.write("<br>" + pkcs10);
document.write("<br>The end!");
}
catch (ex) {
document.write("<br>" + ex.description);
return false;
}

return true;
}

CreateRequest();

</script>

</body>
</html>


Note that if we don't set the right certificate to the KeyArchivalCertificateproperty, we will get the following issue: CertEnroll::CX509Enrollment::p_CreateRequest returns error 0x80070057.


Other issues we may get when creating the request:


- CertEnroll::CX509Enrollment::p_CreateRequest returns error 0x800b0112


- CertEnroll::CX509Enrollment::p_CreateRequest returns error 0x80092012


- CertEnroll::CX509Enrollment::p_CreateRequest returns error 0x8009000b



If we want to install the response from the CA, we may use the same code that we used here:How to create a certificate request with CertEnroll (ASP)or here: How to create a certificate request with CertEnroll (JavaScript). But instead of usingthe .cer orthe .p7b file containing the response, we have to use an .rsp file. What is an .rsp file? What happens if I don't use it? Please, check this post for details: CertEnroll::CX509Enrollment::p_InstallResponse returns error 0x80095002.



I hope this helps.


Regards,


Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/05/27/ndrclientcall2-fails-with-rpc_s_already_listening-when-using-pipes-over-ncalrpc/
Post name: NdrClientCall2 fails with RPC_S_ALREADY_LISTENING when using pipes over ncalrpc
Original author: Alejandro Campos Magencio
Posting date: 2009-05-27T05:29:00+00:00


Hi all,


I've been working on a Microsoft Remote Procedure Call (RPC)issue recently, where the first call to aspecificremote method fails because the call to NdrClientCall2 function in the client stub returns RPC_S_ALREADY_LISTENING("The server is already listening") error. But subsequent calls to the very same method succeed.


The following CONDITIONS are required to reproduce the issue:


1. Process has started its own RPC server (called RpcServerListen) and
2. The same process starts an outgoing RPC call of a method from an interface for which it has no own RPC server started and this method has an "[in] pipe byte" parameter.



In order to better understand the issue, let's consider the following SCENARIO:


- We have 2 processes which useRPCfor interprocess communication. We'll call them A and B.


- Process A and B both run on the same machine. Protocol being used is ncalrpc (Local procedure call). Machine can be either Windows XP or Server 2003.


- We have a MIDL-defined interface that declares a method "rpcMethod" with "[in] pipe byte" parameter like the following:


[
uuid(ActualGuidHere),
version(1.0),
pointer_default(unique)
]
interface IMyInterface
{
//other irrelevant methods here
error_status_t rpcMethod( [in] pipe byte params );
//more irrelevant methods here
}


- An RPC server that implements this interface is started in process B.


- Process A starts its own RPC server for another interface (not the same as process B). While doing this it certainly calls RpcServerListenAPI and that call succeeds.


- Later on, process A tries to invoke IMyInterface::rpcMethod in process B, but call to NdrClientCall2 function fails with RPC_S_ALREADY_LISTENING error and it never reaches the server side.


This error should only be returned when we call RpcServerListentwice on the same process, but we are 100% sure thatwe are only calling it once directly. What is going on then? Why is RPC runtime returning that error? Is it calling RpcServerListen under the hood? Why are the rest of the calls to IMyInterface::rpcMethod succeeding?



The EXPLANATION is the following:


When weuse pipes over ncalrpc, NdrClientCall2 ends upinitializing an ncalrpc endpoint (don't know what an endpoint is? Please check Essential RPC Binding Terminology) for internal use with RpcServerUseProtseqEpAPI andcalling RpcServerListento listen for remote procedure calls, but only if that endpoint has notbeen initialized yet.


The first time we call a method with a pipe parameter, that endpoint for internal use is not initialized yet, so NdrClientCall2 initializes it and calls RpcServerListenwhich fails because we already called it in the same process once before.


The next time we call a method with a pipe parameter, that endpoint is already initialized, so NdrClientCall2 doesn't call RpcServerUseProtseqEp or RpcServerListen. Additionally, we already called RpcServerListen successfully once in that process, so this side is already listening for RPC calls. With the endpoint created and the process listening for RPC calls, everything works just fine from that moment on.



It's very easy to WORKAROUND this limitation: we can safely ignore the RPC_S_ALREADY_LISTENING error of the first call toa method with a pipe parameter and just repeat the call immediately. The failed call won't have any effect andit won't change the pipe state, so there is no need to reinitialize the pipe. There should be no performance impact either.


Note that this issue is related to the usage of pipes over ncalrpc, and it doesn't matter if we use them synchronously or asynchronously (Asynchronous Pipes), or the parameter is [in] or [out]. And of course, the same workaround applies.



Also note that using synchronous pipes over ncalrpc protocol is deprecated on Vista. If you start an application which uses them on Vista, you will see a message like the following on the Event Log:


"
Application ("my program exe file name here" \service) (PID: 344) is using Windows functionality that is not present in this release of Windows. For obtaining an updated version of the application, please, contact the application vendor. The technical information that needs to be conveyed to the application vendor is this: "An RPC method using synchronous pipes has been called on on protocol sequence ncalrpc interface with unique identifier (actual UUID here). Usage and support of synchronous pipes on this protocol sequence has been deprecated for this release of Windows. For information on the deprecation process, please, see <http://go.microsoft.com/fwlink/?LinkId=36415>." User Action Contact the application vendor for updated version of the application.
"


We can still use asynchronous pipes over ncalrpc on Vista,and the RPC_S_ALREADY_LISTENINGissue won't happen.



AnALTERNATE SOLUTIONwhich we recommend and works on all supported versions of Windows is to switch protocols from ncalrpc toncacn_np (Connection-oriented named pipes). Windows components like EFS among others use synchronous pipes over ncacn_np.


Note thatncacn_np transport is remotely accessible, but ncalrpc is not. To keep parity with our existing thread model, we'll need to write our own security callback function and register it with the server (RpcServerRegisterIfEx). The security callback can simply check if the call is coming from local system or remote (RpcServerInqCallAttributesand its IsClientLocal value), and rejects it if it'sa remote client. Or we can update our thread model to deal with remote clients instead.


Sample code:

// Register the security callback with interface
status = RpcServerRegisterIfEx(
hRpcInterface,
NULL, // MgrTypeUuid
NULL, // MgrEpv; null means use default
RPC_IF_ALLOW_LOCAL_ONLY,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
(RPC_IF_CALLBACK_FN*)RpcSecurityCallback
);

RPC_STATUS RPC_ENTRY
RpcSecurityCallback(
IN RPC_IF_HANDLE* handle,
IN void* pCtx)
{
// You can use RpcServerInqCallAttributes API here to find if the client is local or remote.
}



I hope this helps.
Regards,


Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/04/30/default-provider-type-for-cspparameters-has-changed/
Post name: Default Provider Type for CspParameters has changed
Original author: Alejandro Campos Magencio
Posting date: 2009-04-30T10:43:00+00:00


Hi all,


Before .NET Framework 3.5 SP1, the default provider type for CspParameterswas PROV_RSA_FULL (1). Now it's PROV_RSA_AES (24) for all operating systems which support Microsoft Enhanced RSA and AES Cryptographic Provider (WinXP and higher).
So if your code depends on PROV_RSA_FULL being set as provider type, you will have to explicitly specify it yourself:

CspParameters cspParams = new CspParameters();
cspParams.ProviderType = 1;
...
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider(cspParams);
...


You can check which CSPs you have here in the registry:


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider


And here which CSP types we have and the default CSP per type:


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider Types


You can i.e. check type 24 (RSA Full and AES) here:


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider Types\Type 024



I hope this helps.


Regards,



Alex (Alejandro Campos Magencio)