public class PKCS12
extends java.lang.Object
The PKCS#12 Personal Information Exchange Syntax Standard describes a transfer syntax for personal identity information, including private keys, certificates, miscellaneous secrets, and extensions.
This class can be used for securely storing certificates, and private keys with
associated certificates protected by a password. Note that IAIK-JCE also provides
a JCA compliant PKCS#12 KeyStore
implementation as
convenient alternative since it can be used by the accustomed JCA KeyStore API.
Regardless of using the PKCS#12 KeyStore
implementation
or immediately using this PKCS12
class the default algorithms used for
protecting the PKCS#12 object are HMAC_SHA256
as mac algorithm for protecting the integrity of the PKCS#12 object and the PKCS#5
PBES2 scheme PBES2WithHmacSHA256AndAES256
for encrypting (Shrouded)KeyBags contained in
unencrypted AuthenticatedSafe objects and CertBags contained in encrypted AuthenticatedSafe objects.
You can change
the default algorithms to be used. However,
be careful when your PKCS#12 KeyStore(s) must be readable with other PKCS#12 applications, too.
Although we have tested the algorithms to work with well established PKCS#12 applications, it even might
happen that an application may only be able to read PKCS#12 KeyStores protected with the legacy
algorithm set that uses HMAC_SHA1
as mac algorithm, and
the PKCS#5 PBES1 schemes PBEWithSHAAnd40BitRC2_CBC
for encrypting CertBags contained in encrypted AuthenticatedSafe objects and
PBEWithSHAAnd3_KeyTripleDES_CBC
for
encrypting (Shrouded)KeyBags contained in unencrypted AuthenticatedSafe objects. Of course the
legacy set should be used with care because it provides less security than the default
algorithm set. For interoperability reasons the legacy algorithm set has been used as default algorithm
set until IAIK-JCE version 5.62.
When packing the private key into a KeyBag
and certificates
into cert bags
you can specify
locale key id
and friendly name
attributes. When
assigning key id and friendly name attributes you should take care that the
cert bag that contains a certificate with the public key that belongs to the
private key has the same key id and friendly name as the corresponding key
bag. Although attributes are optional some PKCS#12 implementations expect an
attribute for any bag that is included in a PKCS#12 object. Thus, if you have
more than only one certificate you may assign a friendly name attribute to
each certificate bag , e.g. (we assume that we have a private key and a
certificate chain of two certificates with user certificate at index 0 and ca
cert at index 1):
// the certificate chain; user cert at index 0 X509Certificate[] certs = ...; // get the private key PrivateKey privateKey = ...; // we set the commonName as friendlyName attribute Name subject = (Name)certs[0].getSubjectDN(); String friendlyName = subject.getRDN(ObjectID.commonName); // since SubjectKeyIdentifier is included use it as keyId byte[] keyId = ((SubjectKeyIdentifier)certs[0].getExtension(SubjectKeyIdentifier.oid)).get(); // create key bag KeyBag keyBag = new KeyBag(privateKey, friendlyName, keyId); // cert bags; user cert shall be at index (n-1) CertificateBag[] certBags = new CertificateBag[certs.length]; certBags[0] = new CertificateBag(certs[1]); Name caSubject = (Name)certs[1].getSubjectDN(); certBags[0].setFriendlyName(caSubject.getRDN(ObjectID.commonName)); // this certificate corresponds to the private key: certBags[1] = new CertificateBag(certs[0]); certBags[1].setFriendlyName(friendlyName); certBags[1].setLocalKeyID(keyId); // create PKCS12 object PKCS12 pkcs12 = new PKCS12(keyBag, certBags, false); // encrypt with password char[] password = "test".toCharArray(); pkcs12.encrypt(password); // save to file OutputStream os = ...; pkcs12.writeTo(os); os.close();As you see we have created the certificate bags in a way that the user certificate is located at certBags[n-1]. This certificate bag order is expected by some browser versions. The assignment between private key and corresponding certificate bag is done by locale key id and friendly name attribute to know which certificate belongs to the private key when
opening
the PKCS12 file:
// the stream from which to read the PKCS12 object: InputStream is = ...; // create PKCS12 object PKCS12 pkcs12 = new PKCS12(is); // verify MAC if (!pkcs12.verify(password)) { throw new Exception("Verification error!"); } // dercrypt the PKCS#12 object pkcs12.decrypt(password); // get the private key KeyBag kB = pkcs12.getKeyBag(); PrivateKey pk = kB.getPrivateKey(); // get the certificates CertificateBag[] certBag = pkcs12.getCertificateBags(); java.security.cert.Certificate[] certChain = CertificateBag.getCertificates(certBag); // convert to IAIK certs X509Certificate[] certArray = Util.convertCertificateChain(certChain); // we may want to have the end user cert at index 0 certArray = Util.arrangeCertificateChain(certArray, false); // or we may search the cert belonging to the private key based on the localkeyID attribute X509Certificate endUserCert = null; byte[] localKeyID = kB.getLocalKeyID(); if (localKeyID != null) { // check the cert bags for same locale key id for( int i=0; i < certBag.length; i++ ) { byte[] certID = certBag[i].getLocalKeyID(); if ((certID != null) && (CryptoUtils.equalsBlock(certID,localKeyID))) { endUserCert = certBag[i].getCertificate(); break; } } }
SafeBag
,
AuthenticatedSafe
,
KeyBag
,
CertificateBag
Modifier and Type | Field and Description |
---|---|
protected AuthenticatedSafe[] |
authenticated_safes |
protected int |
mode |
static int |
PASSWORD_INTEGRITY_MODE
The password integrity mode.
|
static int |
PUBLIC_KEY_INTEGRITY_MODE
The public-key integrity mode.
|
Constructor and Description |
---|
PKCS12(ASN1Object obj)
Creates a PKCS#12 object from its ASN.1 representation.
|
PKCS12(java.io.InputStream is)
Creates a new PKCS#12 object from its encoding read from an InputStream.
|
PKCS12(KeyBag[] keyBags,
CertificateBag[] certificateBags,
boolean moreSecure)
Deprecated.
the usage of the
moreSecure parameter is deprecated! |
PKCS12(KeyBag keyBag,
CertificateBag[] certificateBags)
Creates a new PKCS#12 object from a KeyBag and an array of CertificateBags.
|
PKCS12(KeyBag keyBag,
CertificateBag[] certificateBags,
boolean moreSecure)
Deprecated.
the usage of the
moreSecure parameter is deprecated! |
Modifier and Type | Method and Description |
---|---|
boolean |
containsMacData()
Asks whether this PKCS12 object contains the MacData element.
|
protected void |
decode()
Decodes this given PKCS#12 object for parsing the internal structure.
|
void |
decrypt(char[] password)
Uses the provided password to decrypt this PKCS12 object for recovering the
inherent authenticatedSafes.
|
void |
encrypt(char[] password)
Uses the provided password to encrypt the content of this PKCS#12 object.
|
void |
encrypt(char[] password,
AlgorithmID authSafesAlg,
AlgorithmID shroudedKeyBagAlg)
Uses the provided password to encrypt the content of this PKCS#12 object.
|
AuthenticatedSafe[] |
getAuthenticatedSafes()
Returns all AuthenticatesSafes included in this PKCS#12 object for manually
parsing.
|
CertificateBag[] |
getCertificateBags()
Returns an array of all CertificateBags within this PKCS#12 object.
|
KeyBag |
getKeyBag()
Tries to find a KeyBag within all AuthenticatedSafes and returns it.
|
KeyBag[] |
getKeyBags()
Tries to find KeyBags within all AuthenticatedSafes and returns them.
|
void |
setBlockSize(int blockSize)
Sets the block size to be used for encoding the inherent Data package.
|
static void |
setDefaultBlockSize(int blockSize)
Sets the default block size to be used for encoding the inherent Data package.
|
void |
setPKCS12Algorithms(PKCS12Algorithms pkcs12Algs)
Sets the algorithms to use.
|
ASN1Object |
toASN1Object()
Returns this PKCS#12 object as ASN1Object.
|
java.lang.String |
toString()
Returns a string giving some information about this
PKCS12
object. |
boolean |
verify(char[] password)
Verifies the MAC of this PKCS12 object.
|
void |
writeTo(java.io.OutputStream os)
Writes this PKCS#12 object to the specified output stream.
|
public static final int PUBLIC_KEY_INTEGRITY_MODE
public static final int PASSWORD_INTEGRITY_MODE
protected AuthenticatedSafe[] authenticated_safes
protected int mode
public PKCS12(KeyBag keyBag, CertificateBag[] certificateBags) throws PKCSException
keyBag
- the SafeBag containing the private keycertificateBags
- the SafeBags containing the users certificate and maybe a chain to
a CAPKCSException
- if the PKCS#12 object can not be created because of an
encoding problem concerning the private key or the
certificatespublic PKCS12(KeyBag keyBag, CertificateBag[] certificateBags, boolean moreSecure) throws PKCSException
moreSecure
parameter is deprecated!keyBag
- the SafeBag containing the private keycertificateBags
- the SafeBags containing the users certificate and maybe a chain to
a CAmoreSecure
- if false
an iteration count of 1 is used for deriving the
keys from the password. This parameter is only available for backwards
compatibility. It is NOT recommended to set moreSecure
to false
!PKCSException
- if the PKCS#12 object can not be created because of an
encoding problem concerning the private key or the
certificatespublic PKCS12(KeyBag[] keyBags, CertificateBag[] certificateBags, boolean moreSecure) throws PKCSException
moreSecure
parameter is deprecated!keyBags
- the key bagscertificateBags
- the certificate bagsmoreSecure
- if false
an iteration count of 1 is used for deriving the
keys from the password. This parameter is only available for backwards
compatibility. It is NOT recommended to set moreSecure
to false
!PKCSException
- if the PKCS#12 object can not be created because of an
encoding problem concerning the keys or the certificatespublic PKCS12(java.io.InputStream is) throws java.io.IOException, PKCSParsingException
is
- the input stream where the object shall be read fromjava.io.IOException
- if the object could not be readPKCSParsingException
- if the object could not be parsedpublic PKCS12(ASN1Object obj) throws PKCSParsingException
obj
- the PKCS12 object as ASN1ObjectPKCSParsingException
- if the ASN1Object could not be parsedpublic static void setDefaultBlockSize(int blockSize)
blockSize
- the default blockSize to be used for Data encoding (system default: 1024 for
indefinite constructed OCTET_STRING encoding; if not positive,
definite primitive encoding will be used)protected void decode() throws PKCSParsingException
PKCSParsingException
- if this object can not be parsedpublic void decrypt(char[] password) throws PKCSException
This method may be used for performing the decryption after creating a
PKCS12
object from a file that has been exported from some
platform, e.g.:
PKCS12 pkcs12 = new PKCS12(new FileInputStream("pkcs12.pfx")); pkcs12.decrypt(password);
This method automatically decrypts all inherent
AuthenticatedSafe
objects that have been encrypted with
password-encrypted privacy mode.
password
- the password to decrypt the PKCS#12 object. null
is a
valid password.PKCSException
- if the PKCS#12 object could not be decryptedpublic AuthenticatedSafe[] getAuthenticatedSafes()
public KeyBag getKeyBag()
public KeyBag[] getKeyBags()
public CertificateBag[] getCertificateBags()
public void setPKCS12Algorithms(PKCS12Algorithms pkcs12Algs)
This method may be used to set the MAC, KeyBag and CertBag algorithm set to be used
to protect this PKCS12 object. By default the PBES2
algorithm
set is used. To switch to the legacy PBES1 algorithm set you may call:
PKCS12 pkcs12 = ...; char[] password = ...; ... pkcs12.setPKCS12Algorithms(PKCS12Algorithms.getLegacy()); pkcs12.encrypt(password); OutputStream os = ...; pkcs12.writeTo(os);When directly refering to the
PBES1
set instead of calling
method getLegay
you should create a clone
of the algorithm set before using it:
PKCS12 pkcs12 = ...; char[] password = ...; ... pkcs12.setPKCS12Algorithms((PKCS12Algorithms)PKCS12Algorithms.PBES1.clone()); pkcs12.encrypt(password); OutputStream os = ...; pkcs12.writeTo(os);Note that any of the algorithms of a PKCS12Algorithms set may use parameters like a salt or iv value that shall not be used twice. Thus, when using this method to set the algorithm set for a PKCS12 object, you anytime may create a new set by calling method
PKCS12Algorithms.getLegacy()
(or, e.g. PKCS12Algorithms.getDefault()
)
or cloning the PKCS12Algorithms.PBES1
(or, e.g. PKCS12Algorithms.PBES2
)
as shown in the example above.pkcs12Algs
- the PKCS12Algorithms set to usepublic boolean containsMacData()
Asking for the presence of the MacData element may be useful before
calling method verify()
to not get an
exception if no mac has been calculated:
PKCS12 pksc12 = ...; ... if (pkcs12.containsMacData()) { if (!pkcs12.verify(password)) { throw new Exception("Mac verification failed!"); } }
true
if this PKCS12 object does contain the MacData element,
false
otherwisepublic boolean verify(char[] password) throws PKCSException
Before verifying the mac it might be advisable to ask
it MacData is included:
PKCS12 pksc12 = ...; ... if (pkcs12.containsMacData()) { if (!pkcs12.verify(password)) { throw new Exception("Mac verification failed!"); } }
password
- the password that was used to protect this PKCS#12 objecttrue
if the MAC turns out to be correct,
false
otherwisePKCSException
- if an error occurs during the verification process (e.g. the
inherent DigestInfo
cannot be parsed; or the MAC
computation fails; or no MacData is included)public void encrypt(char[] password) throws PKCSException
The default algorithms used for protecting the PKCS#12 object are
HMAC_SHA256
as mac algorithm for
protecting the integrity of the PKCS#12 object and the PKCS#5
PBES2 scheme PBES2WithHmacSHA256AndAES256
for encrypting (Shrouded)KeyBags contained in
unencrypted AuthenticatedSafe objects and CertBags contained in encrypted AuthenticatedSafe objects.
The password may even be null
; the result is the same as if a
key is exported from Internet Explorer without providing a password.
password
- the password for performing privacy encryption and integrity MAC
computation. null
is a valid password.PKCSException
- if the PKCS#12 object could not be encryptedpublic void encrypt(char[] password, AlgorithmID authSafesAlg, AlgorithmID shroudedKeyBagAlg) throws PKCSException
The default algorithms used for protecting the PKCS#12 object are
HMAC_SHA256
as mac algorithm for
protecting the integrity of the PKCS#12 object and the PKCS#5
PBES2 scheme PBES2WithHmacSHA256AndAES256
for encrypting (Shrouded)KeyBags contained in
unencrypted AuthenticatedSafe objects and CertBags contained in encrypted AuthenticatedSafe objects.
The password may even be null
; the result is the same as if a
key is exported from Internet Explorer without providing a password.
password
- the password for performing privacy encryption and integrity MAC
computation. null
is a valid password.authSafesAlg
- the PBE algorithm to be used to encrypt authenticated safes
(if null
the AuthSafes cipher algorithm from the
default
algorithm set will be usedshroudedKeyBagAlg
- the PBE algorithm to be used to encrypt the shrouded key bags
(if null
the KeyBag cipher algorithm from the
default
algorithm set will be usedPKCSException
- if the PKCS#12 object could not be encryptedpublic ASN1Object toASN1Object() throws PKCSException
PKCSException
public void writeTo(java.io.OutputStream os) throws java.io.IOException
This method may be used for writing this PFX object to a file to be imported into some platform, e.g.:
pkcs12.writeTo(new FileOutputStream("pkcs12.pfx"));
java.io.IOException
public void setBlockSize(int blockSize)
blockSize
- the blockSize to be used for Data encoding (default: 1024 for
indefinite constructed OCTET_STRING encoding; if not positive,
definite primitive encoding will be used)public java.lang.String toString()
PKCS12
object.toString
in class java.lang.Object