Discussion:
Manual import of pkcs12 file
(too old to reply)
saict
2004-07-26 15:44:44 UTC
Permalink
Hello everyone,

The short question is, how do I programatically import a pkcs12 file
into a certificate store without giving the user the option to settle
for medium or lower security?

A little background:

I've been previously told that this cannot be done in a satisfactory
manner, yet my customers are not accepting this answer. Here's a code
snippet, minus the error checks for clarification:

<begin snippet>

//Read pkcs12 file
/*(1)*/ ReadFile (hFile, pbBuffer, fileSize, &bytesRead, NULL);

//Create pkcs12 CRYPT_DATA_BLOB
pk12Blob.cbData=fileSize;
pk12Blob.pbData=pbBuffer;

//Make sure it's a real PFX blob
/*(2)*/if (PFXIsPFXBlob(&cryptBlob) == FALSE ) goto error;

//Import it, adding user protection
/*(3)*/PFXImportCertStore(&pk12Blob, pk12Password,
CRYPT_USER_KEYSET|CRYPT_USER_PROTECTED);

<end snippet>

At (3), the PFXImportCertStore API brings up some dialogs which
permit, but do not force, the user to add extra protection to the
private key on his certificate. In principle, this could be recoded
to do the job without any user interaction, which is what I'm trying
to do.

Some issues:

1) I think this API decrypts the pkcs12 file by using its password,
and then reformats it into a special microsoft "certificate store"
format. I need to know more than is readily available about what an
HCERTSTORE is, or what it refers to.

2) Possibly, I could parse that PFX blob, and apply a DPAPI call to
just the private key, rewrite the blob and call (3) without the
CRYPT_USER_PROTECTED flag. Would this have the same effect? I.e.,
would the user be prompted for a password each time he requested use
of the private key?

3) Obviously I'm relying on guesswork here. I don't truly know what
goes on behind the scenes of the PFXImportCertStore API. Please tell
me any particulars you can of what this function truly does.

Thanks in advance for your help.
David Cross [MS]
2004-07-27 12:10:22 UTC
Permalink
You cannot programatically control this, but you can set a high setting on
all keys generated or imported:
http://support.microsoft.com/default.aspx?scid=kb;en-us;320828
--
David B. Cross [MS]

--
This posting is provided "AS IS" with no warranties, and confers no rights.

http://support.microsoft.com
Post by saict
Hello everyone,
The short question is, how do I programatically import a pkcs12 file
into a certificate store without giving the user the option to settle
for medium or lower security?
I've been previously told that this cannot be done in a satisfactory
manner, yet my customers are not accepting this answer. Here's a code
<begin snippet>
//Read pkcs12 file
/*(1)*/ ReadFile (hFile, pbBuffer, fileSize, &bytesRead, NULL);
//Create pkcs12 CRYPT_DATA_BLOB
pk12Blob.cbData=fileSize;
pk12Blob.pbData=pbBuffer;
//Make sure it's a real PFX blob
/*(2)*/if (PFXIsPFXBlob(&cryptBlob) == FALSE ) goto error;
//Import it, adding user protection
/*(3)*/PFXImportCertStore(&pk12Blob, pk12Password,
CRYPT_USER_KEYSET|CRYPT_USER_PROTECTED);
<end snippet>
At (3), the PFXImportCertStore API brings up some dialogs which
permit, but do not force, the user to add extra protection to the
private key on his certificate. In principle, this could be recoded
to do the job without any user interaction, which is what I'm trying
to do.
1) I think this API decrypts the pkcs12 file by using its password,
and then reformats it into a special microsoft "certificate store"
format. I need to know more than is readily available about what an
HCERTSTORE is, or what it refers to.
2) Possibly, I could parse that PFX blob, and apply a DPAPI call to
just the private key, rewrite the blob and call (3) without the
CRYPT_USER_PROTECTED flag. Would this have the same effect? I.e.,
would the user be prompted for a password each time he requested use
of the private key?
3) Obviously I'm relying on guesswork here. I don't truly know what
goes on behind the scenes of the PFXImportCertStore API. Please tell
me any particulars you can of what this function truly does.
Thanks in advance for your help.
Hao Zhuang [MSFT]
2004-07-27 17:33:32 UTC
Permalink
just a little clarification: the UI you see _is_ created by DPAPI. so your
approach would have end up the same. you may consider using some GUI hooks.
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Post by David Cross [MS]
You cannot programatically control this, but you can set a high setting on
http://support.microsoft.com/default.aspx?scid=kb;en-us;320828
--
David B. Cross [MS]
--
This posting is provided "AS IS" with no warranties, and confers no rights.
http://support.microsoft.com
Post by saict
Hello everyone,
The short question is, how do I programatically import a pkcs12 file
into a certificate store without giving the user the option to settle
for medium or lower security?
I've been previously told that this cannot be done in a satisfactory
manner, yet my customers are not accepting this answer. Here's a code
<begin snippet>
//Read pkcs12 file
/*(1)*/ ReadFile (hFile, pbBuffer, fileSize, &bytesRead, NULL);
//Create pkcs12 CRYPT_DATA_BLOB
pk12Blob.cbData=fileSize;
pk12Blob.pbData=pbBuffer;
//Make sure it's a real PFX blob
/*(2)*/if (PFXIsPFXBlob(&cryptBlob) == FALSE ) goto error;
//Import it, adding user protection
/*(3)*/PFXImportCertStore(&pk12Blob, pk12Password,
CRYPT_USER_KEYSET|CRYPT_USER_PROTECTED);
<end snippet>
At (3), the PFXImportCertStore API brings up some dialogs which
permit, but do not force, the user to add extra protection to the
private key on his certificate. In principle, this could be recoded
to do the job without any user interaction, which is what I'm trying
to do.
1) I think this API decrypts the pkcs12 file by using its password,
and then reformats it into a special microsoft "certificate store"
format. I need to know more than is readily available about what an
HCERTSTORE is, or what it refers to.
2) Possibly, I could parse that PFX blob, and apply a DPAPI call to
just the private key, rewrite the blob and call (3) without the
CRYPT_USER_PROTECTED flag. Would this have the same effect? I.e.,
would the user be prompted for a password each time he requested use
of the private key?
3) Obviously I'm relying on guesswork here. I don't truly know what
goes on behind the scenes of the PFXImportCertStore API. Please tell
me any particulars you can of what this function truly does.
Thanks in advance for your help.
saict
2004-07-28 00:12:45 UTC
Permalink
Post by Hao Zhuang [MSFT]
just a little clarification: the UI you see _is_ created by DPAPI. so your
approach would have end up the same. you may consider using some GUI hooks.
That's correct, yet I can gain all salient benefits from the DPAPI
without resorting to the UI. If you don't mind clarifying a little
further, what exactly is the nature of the DPAPI call which invokes
the dialog? Is it simply a data protection call against the private
key in the registry after import, is it somehow done against the
CRYPT_DATA_BLOB object before the import takes place, or some other
way?
Hao Zhuang [MSFT]
2004-07-28 03:40:16 UTC
Permalink
in DPAPI CryptProtectData, if you specify the CRYPTPROTECT_PROMPTSTRUCT
structure, with dwPromptFlags = CRYPTPROTECT_PROMPT_ON_PROTECT, DPAPI
automatically shows up the GUI for you.

in PFX, when you do PFXImportCertStore, PFX will try to decode and import
the keys stored in the PFX data to the CSP by CryptImportKey () call. this
function call basically ends up calling CPImportKey of the CSP, which in
case of Microsoft CSPs, DPAPI-protects the keys and writes to the user's key
container files. if CRYPT_USER_PROTECTED flag is on, CryptProtectData is
called with the flag above so that a GUI is shown.

hope this helps !

- hao
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Post by saict
Post by Hao Zhuang [MSFT]
just a little clarification: the UI you see _is_ created by DPAPI. so your
approach would have end up the same. you may consider using some GUI hooks.
That's correct, yet I can gain all salient benefits from the DPAPI
without resorting to the UI. If you don't mind clarifying a little
further, what exactly is the nature of the DPAPI call which invokes
the dialog? Is it simply a data protection call against the private
key in the registry after import, is it somehow done against the
CRYPT_DATA_BLOB object before the import takes place, or some other
way?
saict
2004-07-28 12:44:51 UTC
Permalink
Post by Hao Zhuang [MSFT]
in DPAPI CryptProtectData, if you specify the CRYPTPROTECT_PROMPTSTRUCT
structure, with dwPromptFlags = CRYPTPROTECT_PROMPT_ON_PROTECT, DPAPI
automatically shows up the GUI for you.
in PFX, when you do PFXImportCertStore, PFX will try to decode and import
the keys stored in the PFX data to the CSP by CryptImportKey () call. this
function call basically ends up calling CPImportKey of the CSP, which in
case of Microsoft CSPs, DPAPI-protects the keys and writes to the user's key
container files. if CRYPT_USER_PROTECTED flag is on, CryptProtectData is
called with the flag above so that a GUI is shown.
hope this helps !
- hao
--
This posting is provided "AS IS" with no warranties, and confers no rights.
OK. So if I understand you, it goes like this:

PFXImportCertStore
CryptImportKey
CPImportKey
CryptProtectData

Is the private key itself the only thing being protected? How does the OS
know when it reaches a protected item to request a dialog? Is
CryptProtectData only called once, meaning the default protection is left
off? If not, which protection is done first? The User Credential or the
user-supplied password?

Thanks for your help.
Hao Zhuang [MSFT]
2004-07-30 07:09:03 UTC
Permalink
Post by saict
Is the private key itself the only thing being protected? How does the OS
know when it reaches a protected item to request a dialog? Is
CryptProtectData only called once, meaning the default protection is left
off? If not, which protection is done first? The User Credential or the
user-supplied password?
though i'm not the expert of the exact implementation of the CSP, i believe
it's only the private key being protected, as well as some key meta-data.
public key doesnt need UI protection.

when you are calling function CryptGetUserKey and the CSP acquisition does
not have CRYPT_VERIFYCONTEXT specified, the CSP will consider you intend to
use the private key. then it calls CryptUnprotectData() to decrypt the
private key stored in the CSP's key container. i believe in protecting the
private key, CryptProtectData is only called once. DPAPI will just encrypt
the data with both the user credential and the passwd. that's up to the
implementation of DPAPI.
saict
2004-07-30 19:05:05 UTC
Permalink
Post by Hao Zhuang [MSFT]
Post by saict
Is the private key itself the only thing being protected? How does the OS
know when it reaches a protected item to request a dialog? Is
CryptProtectData only called once, meaning the default protection is left
off? If not, which protection is done first? The User Credential or the
user-supplied password?
though i'm not the expert of the exact implementation of the CSP, i believe
it's only the private key being protected, as well as some key meta-data.
public key doesnt need UI protection.
when you are calling function CryptGetUserKey and the CSP acquisition does
not have CRYPT_VERIFYCONTEXT specified, the CSP will consider you intend to
use the private key. then it calls CryptUnprotectData() to decrypt the
private key stored in the CSP's key container. i believe in protecting the
private key, CryptProtectData is only called once. DPAPI will just encrypt
the data with both the user credential and the passwd. that's up to the
implementation of DPAPI.
Thanks for your help. It makes sense that CryptProtectData would be
only called once. The two things that remain about this mystery are:

1) What is the form of the data passed to CryptImportKey? The output
from CryptProtectData won't work. (At least I assume it won't. After
you encrypt it, how will the CryptImportKey recognize it as a key
blob?) Perhaps you have to encrypt each individual item within the
blob?

2) There must be some auxiliary functionality which gets called in
context if you have protected your private key with a password. It
has to somehow sense that a password has been added so it can prompt
the user for that password before CryptUnprotectData can retrieve it.

Here's some possibilities I can imagine:

Maybe CryptUnprotectData tries to do it's job, and if it fails, it
prompts the user for a password.

Maybe there is some signal written to the registry or to some other
system file, associated with the key, which tells the OS that this key
has password protection.

Maybe there is an inner layer of encryption and an outer layer of
encryption, and the outer layer is an minimally protected block which
includes the information that a password has been added.

Learning, but still confused... :-\
Hao Zhuang [MSFT]
2004-07-31 03:23:56 UTC
Permalink
Post by saict
1) What is the form of the data passed to CryptImportKey? The output
from CryptProtectData won't work. (At least I assume it won't. After
you encrypt it, how will the CryptImportKey recognize it as a key
blob?) Perhaps you have to encrypt each individual item within the
blob?
2) There must be some auxiliary functionality which gets called in
context if you have protected your private key with a password. It
has to somehow sense that a password has been added so it can prompt
the user for that password before CryptUnprotectData can retrieve it.
Maybe CryptUnprotectData tries to do it's job, and if it fails, it
prompts the user for a password.
Maybe there is some signal written to the registry or to some other
system file, associated with the key, which tells the OS that this key
has password protection.
Maybe there is an inner layer of encryption and an outer layer of
encryption, and the outer layer is an minimally protected block which
includes the information that a password has been added.
Learning, but still confused... :-\
1) the CSP only specifies that CryptImportKey should use the same format as
CryptExportKey. it's really up to the implementation of each invidual CSP to
define the format, and it is subject to change. If you read the MSDN on this
function, the data blob passed into CryptImportKey can be pre-encrypted by a
Key handle (NOT DPAPI).

2) CryptProtectData's output data blob does contain information about how
the blob is encrypted, which DPAPI key is used and if there is password,
etc, so that CryptUnprotectData will know what to do.

note that DPAPI encryption/decryption and CSP encryption/decryption are
totally different.

- hao
--
This posting is provided "AS IS" with no warranties, and confers no rights.
saict
2004-07-31 13:33:35 UTC
Permalink
Post by Hao Zhuang [MSFT]
Post by saict
1) What is the form of the data passed to CryptImportKey? The output
from CryptProtectData won't work. (At least I assume it won't. After
you encrypt it, how will the CryptImportKey recognize it as a key
blob?) Perhaps you have to encrypt each individual item within the
blob?
2) There must be some auxiliary functionality which gets called in
context if you have protected your private key with a password. It
has to somehow sense that a password has been added so it can prompt
the user for that password before CryptUnprotectData can retrieve it.
Maybe CryptUnprotectData tries to do it's job, and if it fails, it
prompts the user for a password.
Maybe there is some signal written to the registry or to some other
system file, associated with the key, which tells the OS that this key
has password protection.
Maybe there is an inner layer of encryption and an outer layer of
encryption, and the outer layer is an minimally protected block which
includes the information that a password has been added.
Learning, but still confused... :-\
1) the CSP only specifies that CryptImportKey should use the same format as
CryptExportKey. it's really up to the implementation of each invidual CSP to
define the format, and it is subject to change. If you read the MSDN on this
function, the data blob passed into CryptImportKey can be pre-encrypted by a
Key handle (NOT DPAPI).
OK. I'm reading it from here
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/cryptimportkey.asp
and I didn't get that out of it, but I'll take your word for it. I'm
talking about the Microsoft Enhanced Cryptographic Provider, and when I said
encrypt, I meant with CryptProtectData, not with CryptEncryptMessage. Do
you mean I must use CryptEncryptMessage in this situation? It sounds like
you are saying I can go ahead and encrypt this BLOB before I pass it to
CryptImportKey.
Post by Hao Zhuang [MSFT]
2) CryptProtectData's output data blob does contain information about how
the blob is encrypted, which DPAPI key is used and if there is password,
etc, so that CryptUnprotectData will know what to do.
That sounds great. I'll give it a try.
Post by Hao Zhuang [MSFT]
note that DPAPI encryption/decryption and CSP encryption/decryption are
totally different.
Thank you very much for you help on this.
saict
2004-08-02 16:25:38 UTC
Permalink
Post by Hao Zhuang [MSFT]
Post by saict
1) What is the form of the data passed to CryptImportKey? The output
from CryptProtectData won't work. (At least I assume it won't. After
you encrypt it, how will the CryptImportKey recognize it as a key
blob?) Perhaps you have to encrypt each individual item within the
blob?
2) There must be some auxiliary functionality which gets called in
context if you have protected your private key with a password. It
has to somehow sense that a password has been added so it can prompt
the user for that password before CryptUnprotectData can retrieve it.
Maybe CryptUnprotectData tries to do it's job, and if it fails, it
prompts the user for a password.
Maybe there is some signal written to the registry or to some other
system file, associated with the key, which tells the OS that this key
has password protection.
Maybe there is an inner layer of encryption and an outer layer of
encryption, and the outer layer is an minimally protected block which
includes the information that a password has been added.
Learning, but still confused... :-\
1) the CSP only specifies that CryptImportKey should use the same format as
CryptExportKey. it's really up to the implementation of each invidual CSP to
define the format, and it is subject to change. If you read the MSDN on this
function, the data blob passed into CryptImportKey can be pre-encrypted by a
Key handle (NOT DPAPI).
2) CryptProtectData's output data blob does contain information about how
the blob is encrypted, which DPAPI key is used and if there is password,
etc, so that CryptUnprotectData will know what to do.]
OK, I tried that part. It must be a bit more involved than that. Try
calling CryptProtectData with customized entropy of any type, then
call CryptUnprotectData without that entropy. The latter fails, and
does not prompt the user for the entropy in any way. This seems to
prove that the password dialog is stimulated by some other API, and/or
under some signal separate from the encrypted data itself.
saict
2004-07-27 22:11:53 UTC
Permalink
Post by David Cross [MS]
You cannot programatically control this, but you can set a high setting on
http://support.microsoft.com/default.aspx?scid=kb;en-us;320828
Surely I can programmatically do it if I know what's going on. I
simply need to know what the end result of the function call is. For
example, suppose a user goes through the dialog boxes, choosing high
security and enters an appropriate password and description. The OS
now somehow knows to present a dialog box requesting a password
whenever this key is requested for use. It uses that password and the
user credential to decrypt the key, then uses the key to do its job.

The OS isn't magic. It reacts to some signal in accomplishing all of
this. If I know that signal or signals, I can bring about the same
result.
David Cross [MS]
2004-07-28 13:01:05 UTC
Permalink
There is no programmatic interface difference exposed between high and
medium settings - its not magic, it is just a limited interface that is
exposed. The user chooses high or medium.
--
David B. Cross [MS]

--
This posting is provided "AS IS" with no warranties, and confers no rights.

http://support.microsoft.com
Post by saict
Post by David Cross [MS]
You cannot programatically control this, but you can set a high setting on
http://support.microsoft.com/default.aspx?scid=kb;en-us;320828
Surely I can programmatically do it if I know what's going on. I
simply need to know what the end result of the function call is. For
example, suppose a user goes through the dialog boxes, choosing high
security and enters an appropriate password and description. The OS
now somehow knows to present a dialog box requesting a password
whenever this key is requested for use. It uses that password and the
user credential to decrypt the key, then uses the key to do its job.
The OS isn't magic. It reacts to some signal in accomplishing all of
this. If I know that signal or signals, I can bring about the same
result.
saict
2004-07-28 18:44:49 UTC
Permalink
Post by David Cross [MS]
There is no programmatic interface difference exposed between high and
medium settings - its not magic, it is just a limited interface that is
exposed. The user chooses high or medium.
I don't need anything between high and medium. I need high,
precluding all lesser options.

The DPAPI allows me to do just that, but the cryptographic import APIs
such as PFXImportCertStore and CryptImportKey, which use the DPAPI
themselves, do not pass through the control necessary to accomplish
this.

If I know just a bit about what's going on under the hood I can fix
this up for my clients. I don't think I'm dealing with a proprietary
secret here. I just want to know the particulars of how this key gets
encrypted, and what signals the OS with regard to how it's
encrypted--that is, how does it know to prompt for a password in the
case that high security has been used?
David Cross [MS]
2004-07-31 14:24:20 UTC
Permalink
I am sorry, there are no API methods to set the parameters in DPAPI to do
what you want programatically. Therefore, our team which owns the
PFXImportCertStore API do not have a way to expose this to callers of our
API. I am sorry this is a limitation in the platform, we have passed on
this request to the DPAPI owners for consideration in a future version of
Windows.
--
David B. Cross [MS]

--
This posting is provided "AS IS" with no warranties, and confers no rights.

http://support.microsoft.com
Post by saict
Post by David Cross [MS]
There is no programmatic interface difference exposed between high and
medium settings - its not magic, it is just a limited interface that is
exposed. The user chooses high or medium.
I don't need anything between high and medium. I need high,
precluding all lesser options.
The DPAPI allows me to do just that, but the cryptographic import APIs
such as PFXImportCertStore and CryptImportKey, which use the DPAPI
themselves, do not pass through the control necessary to accomplish
this.
If I know just a bit about what's going on under the hood I can fix
this up for my clients. I don't think I'm dealing with a proprietary
secret here. I just want to know the particulars of how this key gets
encrypted, and what signals the OS with regard to how it's
encrypted--that is, how does it know to prompt for a password in the
case that high security has been used?
tammers
2011-06-18 20:03:09 UTC
Permalink
thurberk wrote on 07/26/2004 11:44 ET
Post by saict
Hello everyone
The short question is, how do I programatically import a pkcs12 fil
into a certificate store without giving the user the option to settl
for medium or lower security
A little background
I've been previously told that this cannot be done in a satisfactor
manner, yet my customers are not accepting this answer. Here's a cod
snippet, minus the error checks for clarification
<begin snippet
//Read pkcs12 fil
/*(1)*/ ReadFile (hFile, pbBuffer, fileSize, &bytesRead, NULL)
//Create pkcs12 CRYPT_DATA_BLO
pk12Blob.cbData=fileSize
pk12Blob.pbData=pbBuffer
//Make sure it's a real PFX blo
/*(2)*/if (PFXIsPFXBlob(&cryptBlob) == FALSE ) goto error
//Import it, adding user protectio
/*(3)*/PFXImportCertStore(&pk12Blob, pk12Password
CRYPT_USER_KEYSET|CRYPT_USER_PROTECTED)
<end snippet
At (3), the PFXImportCertStore API brings up some dialogs whic
permit, but do not force, the user to add extra protection to th
private key on his certificate. In principle, this could be recode
to do the job without any user interaction, which is what I'm tryin
to do
Some issues
1) I think this API decrypts the pkcs12 file by using its password
and then reformats it into a special microsoft "certificate store
format. I need to know more than is readily available about what a
HCERTSTORE is, or what it refers to
2) Possibly, I could parse that PFX blob, and apply a DPAPI call t
just the private key, rewrite the blob and call (3) without th
CRYPT_USER_PROTECTED flag. Would this have the same effect? I.e.
would the user be prompted for a password each time he requested us
of the private key
3) Obviously I'm relying on guesswork here. I don't truly know wha
goes on behind the scenes of the PFXImportCertStore API. Please tel
me any particulars you can of what this function truly does
Thanks in advance for your help
Hello

Someone has achieved the certificate import without any interaction in hig
security mode?

Loading...