<Certificate format="PEM">
<Path>/conf/test.pemcrt</Path>
</Certificate>
- <Key format="DER-PKCS8">
+ <Key format="DER">
<Path>/conf/test.pkcs8.derkey</Path>
</Key>
</FileResolver>
<CAPath>/conf/test.single.2.pemcrt</CAPath>
<CAPath>/conf/test.single.3.pemcrt</CAPath>
</Certificate>
- <Key format="DER-PKCS8">
+ <Key format="DER">
<Path>/conf/test.pkcs8.derkey</Path>
</Key>
</FileResolver>
--- /dev/null
+<?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.pemcrt</Path>
+ </Certificate>
+ <Key format="PEM">
+ <Path>/conf/test.pkcs8.pemkey</Path>
+ </Key>
+ </FileResolver>
+</Credentials>
\ No newline at end of file
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import sun.misc.BASE64Decoder;
+
/**
* @author Walter Hoehn
*
PrivateKey key = null;
- if (keyAlgorithm.equals("RSA") && keyFormat.equals("DER-PKCS8")) {
- try {
- key = getRSADERKey(new ShibResource(keyPath, this.getClass()).getInputStream());
- } catch (IOException ioe) {
- log.error("Could not load resource from specified location (" + keyPath + "): " + e);
- throw new CredentialFactoryException("Unable to load private key.");
+ if (keyAlgorithm.equals("RSA")) {
+
+ if (keyFormat.equals("DER")) {
+ try {
+ key = getRSADERKey(new ShibResource(keyPath, this.getClass()).getInputStream());
+ } catch (IOException ioe) {
+ log.error("Could not load resource from specified location (" + keyPath + "): " + e);
+ throw new CredentialFactoryException("Unable to load private key.");
+ }
+ } else if (keyFormat.equals("PEM")) {
+ try {
+ key = getRSAPEMKey(new ShibResource(keyPath, this.getClass()).getInputStream());
+ } catch (IOException ioe) {
+ log.error("Could not load resource from specified location (" + keyPath + "): " + e);
+ throw new CredentialFactoryException("Unable to load private key.");
+ }
+ } else {
+ log.error("File credential resolver only supports (DER) and (PEM) formats.");
+ throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
}
+
} else {
- log.error("File credential resolver only supports the RSA keys in DER-encoded PKCS8 format (DER-PKCS8).");
+ log.error("File credential resolver only supports the RSA keys.");
throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
}
//TODO provider optional
//TODO provide a way to specify a separate CA bundle
- //The loading code should work for other types, but the chain construction code
+ //The loading code should work for other types, but the chain construction code
//would break
if (!certType.equals("X.509")) {
log.error("File credential resolver only supports the X.509 certificates.");
}
+ private PrivateKey getRSAPEMKey(InputStream inStream) throws CredentialFactoryException {
+
+ try {
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(inStream));
+ String str;
+ boolean insideBase64 = false;
+ StringBuffer base64Key = null;
+ while ((str = in.readLine()) != null) {
+
+ if (insideBase64) {
+ if (str.matches("^.*-----END PRIVATE KEY-----.*$")) {
+ break;
+ }
+ {
+ base64Key.append(str);
+ }
+ } else if (str.matches("^.*-----BEGIN PRIVATE KEY-----.*$")) {
+ insideBase64 = true;
+ base64Key = new StringBuffer();
+ }
+ }
+ in.close();
+ if (base64Key == null || base64Key.length() == 0) {
+ log.error("Did not find BASE 64 encoded private key in file.");
+ throw new CredentialFactoryException("Unable to load private key.");
+ }
+
+ BASE64Decoder decoder = new BASE64Decoder();
+ //Probably want to give a different error for this exception
+ byte[] pkcs8Bytes = decoder.decodeBuffer(base64Key.toString());
+ try {
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Bytes);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePrivate(keySpec);
+
+ } catch (Exception e) {
+ log.error("Unable to load private key: " + e);
+ throw new CredentialFactoryException("Unable to load private key.");
+ }
+ } catch (IOException p) {
+ log.error("Could not load resource from specified location: " + p);
+ throw new CredentialFactoryException("Unable to load key.");
+ }
+ }
+
private String getCertFormat(Element e) throws CredentialFactoryException {
NodeList certificateElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "Certificate");
log.debug("No format specified for certificate, using default (PEM) format.");
format = "PEM";
}
-
- if (!format.equals("DER-PKCS8")) {
- log.error("File credential resolver currently only supports (DER-PKCS8) format.");
- throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
- }
-
+ //TODO smarter
+ /*
+ * if (!format.equals("DER-PKCS8")) { log.error("File credential resolver currently only supports (DER-PKCS8)
+ * format."); throw new CredentialFactoryException("Failed to initialize Credential Resolver."); }
+ */
return format;
}
/**
*
- * Loads a specified bundle of certs individually and returns an array of
- * <code>Certificate</code> objects. This is needed because the standard
- * <code>CertificateFactory.getCertificates(InputStream)</code> method bails
- * out when it has trouble loading any cert and cannot handle "comments".
+ * Loads a specified bundle of certs individually and returns an array of <code>Certificate</code> objects. This
+ * is needed because the standard <code>CertificateFactory.getCertificates(InputStream)</code> method bails out
+ * when it has trouble loading any cert and cannot handle "comments".
*/
private Certificate[] loadCertificates(InputStream inStream, String certType) throws CredentialFactoryException {
}
/**
- * Given an ArrayList containing a base certificate and an array of unordered certificates,
- * populates the ArrayList with an ordered certificate chain, based on subject and issuer.
+ * Given an ArrayList containing a base certificate and an array of unordered certificates, populates the ArrayList
+ * with an ordered certificate chain, based on subject and issuer.
*
- * @param chainSource array of certificates to pull from
- * @param chainDest ArrayList containing base certificate
- * @throws InvalidCertificateChainException thrown if a chain cannot be constructed from
- * the specified elements
+ * @param chainSource
+ * array of certificates to pull from
+ * @param chainDest
+ * ArrayList containing base certificate
+ * @throws InvalidCertificateChainException
+ * thrown if a chain cannot be constructed from the specified elements
*/
protected void walkChain(X509Certificate[] chainSource, ArrayList chainDest) throws CredentialFactoryException {
/**
* Boolean indication of whether a given private key and public key form a valid keypair.
*
- * @param pubKey the public key
- * @param privKey the private key
+ * @param pubKey
+ * the public key
+ * @param privKey
+ * the private key
*/
protected boolean isMatchingKey(PublicKey pubKey, PrivateKey privKey) {
buffer = b;
}
- /**
- * Returns an array of the bytes in the container. <p>
+ /**
+ * Returns an array of the bytes in the container.
+ * <p>
*/
private byte[] toByteArray() {
return b;
}
- /**
+ /**
* Add one byte to the end of the container.
*/
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,24D0AC0A45FE49C6
+
++NPze4BLeIFQZiQtGM1c8vrkhJmA9HRknIk+YfCE2lEpcz9Ccg19WuDIrJrtAJ7q
+w1v7m4T2FfHv5Xbh+op+EWmuxz3FdI6VWNvu+lHIM43FuFe6qh2BAid0SVm5uD1m
+LTeOQk0pMIov55GkSEhdxs5KqFVHrsqSGs9ELRIvAj0Ib6BkMR032m3DvYPJgTmH
+65OLkgYw8R6c7OhYCaxlpUtwGvMklHirek05V31qn3zpW6TDQ2qBvylJqt5oCtt1
+Zx/AByDhLx2OiUmrRv12nwjdUtyLo7WvNfsHVg3Kk7rlZtK0LMlKC2GIhP2ibqgk
+Q3WYLZ+6JJfHAvV9xHlhPpK98Z0D6jGgFGKzgct0ttwwjTNFUwU8+J8YHKHD9Ts0
+QyQa7JASLApmgknDHH6T8RdVlMRhsC4R9es2IMcPqWW3zckEM5uwzMScmSRlCyIy
+ZkEu9NKWEQdcFnSNp/SGzOd2iX36LKXHDvQsGu1ewIO1d58vgYOYjZbjFFSCnIyC
+gsCFD/USLDFW0Qpq+rl9J1oLPfFCKiDlCwsBg8E9hw9ZwMzij9olq+qycoXtH6Eo
+kWpkndxeQ8GWkXw5D+hcOfbeOT4ABLQwVjXRF/RB+T/14R4BLxjzEGlBBg2ltmYL
+gi5Y1pYTy+6x7DGepLIvYiuaDhyD2XpCVj0b3vqfrWpsjmftJI9CQNHef3/ZSgfT
+07CJHtUeWWF0JTVrLrN8EZT/0t6t0n1nY1CUnIYDDRw+9a/6rK8t8IZMlI2Hf19b
+SOaTzMaAQt8VYH767PE/yuPyB4QLLL8Dg9dHDYvdf1OuF/5JypTrFg==
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDMVK9L2pr9Swf2gkf67VAztznU/rujBFyoRRGFMOy1PdYEOw/n
+5hMgZSLAkyQziFAgjrIwjuKfoPNuEZDH1P+rrFGpcVeouTWetz+Ryz6FtHhPXXDB
+bq93WTe4FQcldX47O8wTDPZJLRHEVkPDkwaXAkaqTB7nA83pBRbMLG+myQIDAQAB
+AoGAEfCVe3l0Bi0iQ9hobXWMhx3dLAA5hTSK1hNKWIFVJwyIz9JHsTqYD04R4QqK
+MSQUtOcSagUBjLZa6R0Nsx3WXJoIuV3rkN4eTuE25hkpcpY2gxnk1rB4o2+oiRUR
+dBiG6nOIyJ7kLaCa1azlW1I8J+2B3D6SLY96Mg7VxiMedukCQQDyDuTtUCndXTEe
+vkTCmwqQGKtt0Adxqa8OMHZxF+qDmIuMCSAgl1IERy8g9vVlqbLWP0w5oL2x2IOt
+NeAus7YjAkEA2BmBwDpyaldzC3qoakWHFKn4c1LAsVRErRZZrtr6ykFh/FHYsC8R
+/zdlFMaciyw2DM5AmaMVOcQ1sTk8vydAIwJADVv3FIXlGZuIF3tGzjrCVXuXEoN1
+tbc4ux6/mrRINCUaJotmY4YWd7f6COa4WnkILrzllxShA4zAj7G2gr1WYwJBALxQ
+DeeLhyTwK8q3CogBKqNxMpacaFqfSnFi5qgfHyidLVwJnsB5ZD948FbYdJY64qbq
+HRVFLjv2patYa31QIO0CQFWN+bleiLXOSkI6bDLMeQk+SikeHgdNIgomQGDpYu5d
+iBsIHDdqpiteqW6qcZNqd7YDYSSgKTtVo/A2cPkN7zw=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoTAbBgkqhkiG9w0BBQMwDgQIUFkGlrGEVNsCAggABIICgIcFP7A3nik//yA5
+jb8iiIqUZIHLPGpaxldbrr4LRJAT/o4+zwtthMsVe8K3jg05Sid3+LJUYVZVKfxF
+kDu/fQtYL9vbyze3GawaDhrlsv77CEQB677OlI0er12QlhLjXuf4bKIkYzSwf+cF
+Tb+ROarggvv/Z3xYZU4xCrMHjEZLxnJLXeQ3i9PV0MznY2grQRI7jcv9UTUDCGfC
+sVn+yotMht4+7ttvJw7cfMh4VdlkBRZJkBBCIlEjENBAJWyZblsQKOLY40OslzHO
+TB2j0y/rY3iMgVW2rU4nrbGoFgLpmQcA7c93gx0mfBnSGTciGP6HeefXGqchsEiN
+oYHS7msaH++AJYWEK6J9mLU9zjwzapSNr/QFbcQ+c6SoKtoyWdWAI+eN5vhvDPnd
+SeG8wwvL3aWMYPOvnZQ0OidcHKAwh8hXu8bk6SOoRtXaqCu5kIjdLtvxhxzcPjvF
+aNhk+B2BbnvFMYLVHCwW+apiSsgMG9WX95/S49g6MqKEc4+g5ecGe+pMNXieXcp6
+ngPyjFyzUOjWdsDZU3MCDsvqFfKJXCN2KFrdKg0mISOh8wpzbvfghsay7vWTiI1W
+NLPEDv3CPzmJaHxqVHlKKbCuGPPUGibaNw0LygK7fWbgV0oZoAgMNXNuvw5Xvu7n
+s5Xw20q8Jv5F1E8w+Bz5JeUzF3gIM9BbEpYDMQPtyPB/xZw0ZETr2Muaufv7Xm1i
+qdvwyFf8Mpx860QD5mzHC3ivCwjjqjO8xCCiKdNMy/t6mJQ7gjCiVUwEAvYAOViu
+UVIJisYqkGIlKu5cz2ykw7JOKQ6j7Npgf1ndUoOTGkejsVVQfe8+bTEq6DZalmUh
+PWGEfig=
+-----END ENCRYPTED PRIVATE KEY-----
--- /dev/null
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMxUr0vamv1LB/aC
+R/rtUDO3OdT+u6MEXKhFEYUw7LU91gQ7D+fmEyBlIsCTJDOIUCCOsjCO4p+g824R
+kMfU/6usUalxV6i5NZ63P5HLPoW0eE9dcMFur3dZN7gVByV1fjs7zBMM9kktEcRW
+Q8OTBpcCRqpMHucDzekFFswsb6bJAgMBAAECgYAR8JV7eXQGLSJD2GhtdYyHHd0s
+ADmFNIrWE0pYgVUnDIjP0kexOpgPThHhCooxJBS05xJqBQGMtlrpHQ2zHdZcmgi5
+XeuQ3h5O4TbmGSlyljaDGeTWsHijb6iJFRF0GIbqc4jInuQtoJrVrOVbUjwn7YHc
+PpItj3oyDtXGIx526QJBAPIO5O1QKd1dMR6+RMKbCpAYq23QB3Gprw4wdnEX6oOY
+i4wJICCXUgRHLyD29WWpstY/TDmgvbHYg6014C6ztiMCQQDYGYHAOnJqV3MLeqhq
+RYcUqfhzUsCxVEStFlmu2vrKQWH8UdiwLxH/N2UUxpyLLDYMzkCZoxU5xDWxOTy/
+J0AjAkANW/cUheUZm4gXe0bOOsJVe5cSg3W1tzi7Hr+atEg0JRomi2ZjhhZ3t/oI
+5rhaeQguvOWXFKEDjMCPsbaCvVZjAkEAvFAN54uHJPAryrcKiAEqo3EylpxoWp9K
+cWLmqB8fKJ0tXAmewHlkP3jwVth0ljripuodFUUuO/alq1hrfVAg7QJAVY35uV6I
+tc5KQjpsMsx5CT5KKR4eB00iCiZAYOli7l2IGwgcN2qmK16pbqpxk2p3tgNhJKAp
+O1Wj8DZw+Q3vPA==
+-----END PRIVATE KEY-----
throw new SAXException("Could not load entity: " + e);
}
} else if (systemId.endsWith("xmldsig-core-schema.xsd")) {
- InputStream stream;
- try {
- stream = new FileInputStream("src/schemas/xmldsig-core-schema.xsd");
- if (stream != null) {
- return new InputSource(stream);
+ InputStream stream;
+ try {
+ stream = new FileInputStream("src/schemas/xmldsig-core-schema.xsd");
+ if (stream != null) {
+ return new InputSource(stream);
+ }
+ throw new SAXException("Could not load entity: Null input stream");
+ } catch (FileNotFoundException e) {
+ throw new SAXException("Could not load entity: " + e);
}
- throw new SAXException("Could not load entity: Null input stream");
- } catch (FileNotFoundException e) {
- throw new SAXException("Could not load entity: " + e);
- }
- }else {
+ } else {
return null;
}
}
fail("Failed to load credentials: " + e);
}
}
-
+
public void testKeyStoreX509AliasDefaulting() {
try {
fail("Failed to load credentials: " + e);
}
}
-
+
public void testFileX509NoPassword() {
try {
fail("Failed to load credentials: " + e);
}
}
-
+
public void testFileX509withCABundles() {
try {
}
}
+ public void testKeyStoreX509_PEM_PKCS8Key() {
+
+ try {
+ InputStream inStream = new FileInputStream("data/credentials5.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=shib2.internet2.edu, OU=Unknown, O=Unknown, ST=Unknown, C=Unknown");
+ assertEquals(
+ "Unexpected certificate chain length.",
+ new Integer(credential.getX509CertificateChain().length),
+ new Integer(3));
+ assertEquals(
+ "Unexpected X509 certificate found.",
+ credential.getX509CertificateChain()[2].getSubjectDN().getName(),
+ "CN=HEPKI Master CA -- 20020701A, OU=Division of Information Technology, O=University of Wisconsin, L=Madison, ST=Wisconsin, C=US");
+ } catch (Exception e) {
+ fail("Failed to load credentials: " + e);
+ }
+ }
+
}