Add support for PEM-encoded PKCS8 format DSA keys. Auto-detect key type for PKCS8.
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 5 Dec 2003 04:55:42 +0000 (04:55 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Fri, 5 Dec 2003 04:55:42 +0000 (04:55 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@802 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

data/credentials10.xml [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/common/Credentials.java
tests/conf/test.dsa.pkcs8.pemkey [new file with mode: 0644]
tests/edu/internet2/middleware/shibboleth/common/CredentialsTests.java

diff --git a/data/credentials10.xml b/data/credentials10.xml
new file mode 100644 (file)
index 0000000..576a358
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Credentials xmlns="urn:mace:shibboleth:credentials:1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+       xsi:schemaLocation="urn:mace:shibboleth:credentials:1.0 credentials.xsd">
+       
+       <FileResolver Id="test">
+               <Certificate format="PEM">
+                       <Path>/conf/test.dsa.pemcrt</Path>
+               </Certificate>
+               <Key format="PEM">
+                       <Path>/conf/test.dsa.pkcs8.pemkey</Path>
+               </Key>
+       </FileResolver>
+</Credentials>
\ No newline at end of file
index 26facd7..f3b5eba 100644 (file)
@@ -171,6 +171,9 @@ class FileCredentialResolver implements CredentialResolver {
 
        private static Logger log = Logger.getLogger(FileCredentialResolver.class.getName());
 
+       private static String DSAKey_OID = "1.2.840.10040.4.1";
+       private static String RSAKey_OID = "1.2.840.113549.1.1.1";
+
        public Credential loadCredential(Element e) throws CredentialFactoryException {
 
                if (!e.getTagName().equals("FileResolver")) {
@@ -191,7 +194,6 @@ class FileCredentialResolver implements CredentialResolver {
                log.debug("Key Path: (" + keyPath + ").");
 
                //TODO support DER, PEM, DER-PKCS8, and PEM-PKCS8?
-               //TODO DSA
 
                PrivateKey key = null;
 
@@ -333,6 +335,7 @@ class FileCredentialResolver implements CredentialResolver {
                } while (i > -1);
 
                //TODO switch to examining the DER, so we don't get failure messages
+               //TODO support DSA when switching
                try {
                        return getRSAPkcs8DerKey(inputBytes.toByteArray());
 
@@ -367,8 +370,9 @@ class FileCredentialResolver implements CredentialResolver {
                while ((str = in.readLine()) != null) {
 
                        if (str.matches("^.*-----BEGIN PRIVATE KEY-----.*$")) {
+                               log.debug("Key appears to be in PKCS8 format.");
                                in.close();
-                               return getPkcs8PemKey(
+                               return getPkcs8Key(
                                        singleDerFromPEM(
                                                inputBytes.toByteArray(),
                                                "-----BEGIN PRIVATE KEY-----",
@@ -376,6 +380,7 @@ class FileCredentialResolver implements CredentialResolver {
 
                        } else if (str.matches("^.*-----BEGIN RSA PRIVATE KEY-----.*$")) {
                                in.close();
+                               log.debug("Key appears to be RSA in raw format.");
                                return getRSARawDERKey(
                                        singleDerFromPEM(
                                                inputBytes.toByteArray(),
@@ -383,6 +388,7 @@ class FileCredentialResolver implements CredentialResolver {
                                                "-----END RSA PRIVATE KEY-----"));
                        } else if (str.matches("^.*-----BEGIN DSA PRIVATE KEY-----.*$")) {
                                in.close();
+                               log.debug("Key appears to be DSA in raw format.");
                                return getDSARawDERKey(
                                        singleDerFromPEM(
                                                inputBytes.toByteArray(),
@@ -407,7 +413,19 @@ class FileCredentialResolver implements CredentialResolver {
                        log.error("Unable to load private key: " + e);
                        throw new CredentialFactoryException("Unable to load private key.");
                }
+       }
+
+       private PrivateKey getDSAPkcs8DerKey(byte[] bytes) throws CredentialFactoryException {
 
+               try {
+                       KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+                       PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
+                       return keyFactory.generatePrivate(keySpec);
+
+               } catch (Exception e) {
+                       log.error("Unable to load private key: " + e);
+                       throw new CredentialFactoryException("Unable to load private key.");
+               }
        }
 
        private PrivateKey getRSARawDERKey(byte[] bytes) throws CredentialFactoryException {
@@ -530,10 +548,46 @@ class FileCredentialResolver implements CredentialResolver {
 
        }
 
-       private PrivateKey getPkcs8PemKey(byte[] bytes) throws CredentialFactoryException {
+       private PrivateKey getPkcs8Key(byte[] bytes) throws CredentialFactoryException {
+
+               try {
+                       DerValue root = new DerValue(bytes);
+                       if (root.tag != DerValue.tag_Sequence) {
+                               log.error("Unexpected data type.  Unable to load data as a PKCS8 formatted key.");
+                               throw new CredentialFactoryException("Unable to load private key.");
+                       }
+
+                       DerValue[] childValues = new DerValue[2];
+                       childValues[0] = root.data.getDerValue();
+                       childValues[1] = root.data.getDerValue();
 
-               //TODO Needs to work for DSA as well
-               return getRSAPkcs8DerKey(bytes);
+                       if (childValues[0].tag != DerValue.tag_Integer || childValues[1].tag != DerValue.tag_Sequence) {
+                               log.error("Unexpected data type.  Unable to load data as a PKCS8 formatted key.");
+                               throw new CredentialFactoryException("Unable to load private key.");
+                       }
+
+                       DerValue grandChild = childValues[1].data.getDerValue();
+                       if (grandChild.tag != DerValue.tag_ObjectId) {
+                               log.error("Unexpected data type.  Unable to load data as a PKCS8 formatted key.");
+                               throw new CredentialFactoryException("Unable to load private key.");
+                       }
+
+                       String keyOID = grandChild.getOID().toString();
+                       if (keyOID.equals(FileCredentialResolver.RSAKey_OID)) {
+                               log.debug("Found RSA key in PKCS8.");
+                               return getRSAPkcs8DerKey(bytes);
+                       } else if (keyOID.equals(FileCredentialResolver.DSAKey_OID)) {
+                               log.debug("Found DSA key in PKCS8.");
+                               return getDSAPkcs8DerKey(bytes);
+                       } else {
+                               log.error("Unexpected key type.  Only RSA and DSA keys are supported in PKCS8 format.");
+                               throw new CredentialFactoryException("Unable to load private key.");
+                       }
+
+               } catch (IOException e) {
+                       log.error("Invalid DER encoding for PKCS8 formatted key: " + e);
+                       throw new CredentialFactoryException("Unable to load private key.");
+               }
        }
 
        private byte[] singleDerFromPEM(byte[] bytes, String beginToken, String endToken) throws IOException {
diff --git a/tests/conf/test.dsa.pkcs8.pemkey b/tests/conf/test.dsa.pkcs8.pemkey
new file mode 100644 (file)
index 0000000..7ef3e62
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN PRIVATE KEY-----
+MIICTgIBADCCAi4GByqGSM44BAEwggIhAoIBAQDe9s7lK48JAu83X1Z9pXtms/uN
+kh1cg3PacoIwRhcFP6l5ZWPeve9viDVZPxHuGZOv9lsO5Om/wiOmVcbwmt/BgVfb
+rt+Jpk2m8xQWpgcOMIM/U6OJbL9VUF3bDFByEEeCjpGaXGYDqSo8aCQIUPXLvDp4
+seGgBKXdiJ7xDk/0mHabVd54UFB/KuiqTbCCJKU4oH7mlZ5NtVTERtd1qR9jfeCL
+maO2+oDac3tzq9VqziuiGATQ7AE7z75QmGKwym0lpj+JiVkt4oFgNE9XoX+re2tw
+JobGouR4PZ5KlaiY1BOF4rIZF71pu7gUpVQRPIkzhNNLu5MpduT3kxpCzlTvAhUA
+rLcSAAuPIAwq6EXxrqR7YVYUHjECggEBAInCYaH9/llDRAWeH3HUWeJchCcBnpmZ
+zTKzkvTotBMBmqN7JitOMUzsGc3IBGAsRfexhtXo1tSE9k4vioOnqhT7kVpkKEBr
+IB51NGiV/y0feJm61gw9a958M7BDCLI4n1gDp2/MahBQAbWoRM64U8z6Pr55rLRv
+EW9VUDZfSF6tkHaZTAgT19tq6t834KtvS+EVCrqhfW4I7t9dsBAbhx2626/Ot2UF
+8GU5WxezjrmLQcV25Yre7/uOp0STEbVqfwziezTl8VrPS+NfJ33y0GY+kqSiWcEH
+5whED3m2UbkbE8pQ0rVzNRWiUz2IpqQ8E6ixpPI2Ayt46ef+MP66/HEEFwIVAKmy
+99Zl6BksaNSh3+cuCnySiSCM
+-----END PRIVATE KEY-----
index d06dccf..00e4e82 100644 (file)
@@ -405,5 +405,32 @@ public class CredentialsTests extends TestCase {
                        fail("Failed to load credentials: " + e);
                }
        }
+       
+       public void testKeyStoreX509_PEM_PKCS8_DSA_Key() {
+
+               try {
+                       InputStream inStream = new FileInputStream("data/credentials10.xml");
+                       parser.parse(new InputSource(inStream));
+                       Credentials credentials = new Credentials(parser.getDocument().getDocumentElement());
+
+                       assertTrue("Credential could not be found.", credentials.containsCredential("test"));
+                       Credential credential = credentials.getCredential("test");
+
+                       assertTrue(
+                               "Credential was loaded with an incorrect type.",
+                               credential.getCredentialType() == Credential.X509);
+                       assertNotNull("Private key was not loaded correctly.", credential.getPrivateKey());
+                       assertEquals(
+                               "Unexpected X509 certificate found.",
+                               credential.getX509Certificate().getSubjectDN().getName(),
+                               "CN=test.columbia.edu, OU=ACIS, O=Columbia University, L=New York, ST=NY, C=US");
+                       assertEquals(
+                               "Unexpected certificate chain length.",
+                               new Integer(credential.getX509CertificateChain().length),
+                               new Integer(1));
+               } catch (Exception e) {
+                       fail("Failed to load credentials: " + e);
+               }
+       }
 
 }