View Javadoc
1   /*-
2    * #%L
3    * io.earcam.utilitarian.security
4    * %%
5    * Copyright (C) 2017 earcam
6    * %%
7    * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
8    *
9    * You <b>must</b> choose to accept, in full - any individual or combination of
10   * the following licenses:
11   * <ul>
12   * 	<li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
13   * 	<li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
14   * 	<li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
15   * 	<li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
16   * </ul>
17   * #L%
18   */
19  package io.earcam.utilitarian.security;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.security.KeyPair;
24  import java.security.KeyStore;
25  import java.security.KeyStore.LoadStoreParameter;
26  import java.security.PrivateKey;
27  import java.security.cert.Certificate;
28  
29  import io.earcam.unexceptional.Exceptional;
30  
31  public class KeyStores {
32  
33  	private KeyStores()
34  	{}
35  
36  
37  	public static KeyPair keyPair(KeyStore store, String alias, char[] password)
38  	{
39  		PrivateKey key = PrivateKey.class.cast(Exceptional.apply(store::getKey, alias, password));
40  		Certificate certificate = Exceptional.apply(store::getCertificate, alias);
41  		return new KeyPair(certificate.getPublicKey(), key);
42  	}
43  
44  
45  	public static KeyStore keyStore(KeyPairCredential credential, Certificate... certificates)
46  	{
47  		return keyStore(credential.name(), credential.password(), credential.pair(), certificates);
48  	}
49  
50  
51  	/**
52  	 * 
53  	 * @param alias key alias
54  	 * @param aliasPassword password
55  	 * @param pair the key pair to use
56  	 * @param certificates
57  	 * @return a KeyStore built from the supplied arguments
58  	 * @throws io.earcam.unexceptional.UncheckedSecurityException if {@link java.security.KeyStoreException},
59  	 * {@link java.security.NoSuchAlgorithmException} or {@link java.security.cert.CertificateException} is raised
60  	 * @throws java.io.UncheckedIOException if java.io.IOException is raised
61  	 */
62  	public static KeyStore keyStore(String alias, char[] aliasPassword, KeyPair pair, Certificate... certificates)
63  	{
64  		return keyStore("JKS", alias, aliasPassword, pair, certificates);
65  	}
66  
67  
68  	/**
69  	 * 
70  	 * @param type
71  	 * @param alias key alias
72  	 * @param aliasPassword password
73  	 * @param pair the key pair to use
74  	 * @param certificates
75  	 * @return a KeyStore built from the supplied arguments
76  	 * @throws io.earcam.unexceptional.UncheckedSecurityException if {@link java.security.KeyStoreException},
77  	 * {@link java.security.NoSuchAlgorithmException} or {@link java.security.cert.CertificateException} is raised
78  	 * @throws java.io.UncheckedIOException if java.io.IOException is raised
79  	 */
80  	public static KeyStore keyStore(String type, String alias, char[] aliasPassword, KeyPair pair, Certificate... certificates)
81  	{
82  		KeyStore keyStore = Exceptional.apply(KeyStore::getInstance, type);
83  		Exceptional.accept(keyStore::load, (LoadStoreParameter) null);
84  		Exceptional.run(() ->
85  		// TODO check - if there are no certificates then we should not provide the private key but the public?
86  		keyStore.setKeyEntry(alias, pair.getPrivate(), aliasPassword, certificates));
87  		return keyStore;
88  	}
89  
90  
91  	/**
92  	 * 
93  	 * @param keyStore
94  	 * @param password
95  	 * @return
96  	 * @throws io.earcam.unexceptional.UncheckedSecurityException if {@link java.security.KeyStoreException},
97  	 * {@link java.security.NoSuchAlgorithmException} or {@link java.security.cert.CertificateException} is raised
98  	 * @throws java.io.UncheckedIOException if java.io.IOException is raised
99  	 */
100 	public static byte[] encode(KeyStore keyStore, char[] password)
101 	{
102 		ByteArrayOutputStream output = new ByteArrayOutputStream();
103 		Exceptional.accept(keyStore::store, output, password);
104 		return output.toByteArray();
105 	}
106 
107 
108 	/**
109 	 * 
110 	 * @param dehydrated
111 	 * @param password
112 	 * @return
113 	 * @throws io.earcam.unexceptional.UncheckedSecurityException if {@link java.security.KeyStoreException},
114 	 * {@link java.security.NoSuchAlgorithmException} or {@link java.security.cert.CertificateException} is raised
115 	 * @throws java.io.UncheckedIOException if java.io.IOException is raised
116 	 */
117 	public static KeyStore decode(byte[] dehydrated, char[] password)
118 	{
119 		return decode("JKS", dehydrated, password);
120 	}
121 
122 
123 	/**
124 	 * 
125 	 * @param type
126 	 * @param dehydrated
127 	 * @param password
128 	 * @return
129 	 * @throws io.earcam.unexceptional.UncheckedSecurityException if {@link java.security.KeyStoreException},
130 	 * {@link java.security.NoSuchAlgorithmException} or {@link java.security.cert.CertificateException} is raised
131 	 * @throws java.io.UncheckedIOException if java.io.IOException is raised
132 	 */
133 	public static KeyStore decode(String type, byte[] dehydrated, char[] password)
134 	{
135 		KeyStore rehydrated = Exceptional.apply(KeyStore::getInstance, type);
136 		Exceptional.accept(rehydrated::load, new ByteArrayInputStream(dehydrated), password);
137 		return rehydrated;
138 	}
139 }