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 }