/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm.config.value; import org.jdom2.Element; import password.pwm.bean.PrivateKeyCertificate; import password.pwm.config.PwmSetting; import password.pwm.config.StoredValue; import password.pwm.util.java.JsonUtil; import password.pwm.util.java.StringUtil; import password.pwm.util.secure.X509Utils; import password.pwm.util.logging.PwmLogger; import password.pwm.util.secure.PwmBlockAlgorithm; import password.pwm.util.secure.PwmSecurityKey; import password.pwm.util.secure.SecureEngine; import java.io.Serializable; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; public class PrivateKeyValue extends AbstractValue { private static final PwmLogger LOGGER = PwmLogger.forClass(PrivateKeyValue.class); private static final String ELEMENT_NAME_CERTIFICATE = "certificate"; private static final String ELEMENT_NAME_KEY = "key"; private PrivateKeyCertificate privateKeyCertificate; public static StoredValue.StoredValueFactory factory() { return new StoredValue.StoredValueFactory() { public PrivateKeyValue fromXmlElement(final Element settingElement, final PwmSecurityKey key) { if (settingElement != null && settingElement.getChild("value") != null) { final Element valueElement = settingElement.getChild("value"); if (valueElement != null) { final List<X509Certificate> certificates = new ArrayList<>(); for (final Element certificateElement : valueElement.getChildren(ELEMENT_NAME_CERTIFICATE)) { try { final String b64Text = certificateElement.getText(); final X509Certificate cert = X509Utils.certificateFromBase64(b64Text); certificates.add(cert); } catch (Exception e) { LOGGER.error("error reading certificate: " + e.getMessage(),e); } } PrivateKey privateKey = null; try { final Element keyElement = valueElement.getChild(ELEMENT_NAME_KEY); final String encryptedText = keyElement.getText(); final String decryptedText = SecureEngine.decryptStringValue(encryptedText, key, PwmBlockAlgorithm.CONFIG); final byte[] privateKeyBytes = StringUtil.base64Decode(decryptedText); privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); } catch (Exception e) { LOGGER.error("error reading privateKey: " + e.getMessage(),e); } if (!certificates.isEmpty() && privateKey != null) { final X509Certificate[] certs = certificates.toArray(new X509Certificate[certificates.size()]); final PrivateKeyCertificate privateKeyCertificate = new PrivateKeyCertificate(certs, privateKey); return new PrivateKeyValue(privateKeyCertificate); } } } return new PrivateKeyValue(null); } public X509CertificateValue fromJson(final String input) { return new X509CertificateValue(new X509Certificate[0]); } }; } public PrivateKeyValue(final PrivateKeyCertificate privateKeyCertificate) { this.privateKeyCertificate = privateKeyCertificate; } public List<Element> toXmlValues(final String valueElementName) { throw new IllegalStateException("password xml output requires hash key"); } @Override public Object toNativeObject() { return privateKeyCertificate; } @Override public List<String> validateValue(final PwmSetting pwm) { return Collections.emptyList(); } @Override public int currentSyntaxVersion() { return 0; } public List<Element> toXmlValues(final String valueElementName, final PwmSecurityKey key) { final Element valueElement = new Element("value"); if (privateKeyCertificate != null) { try { { for (final X509Certificate certificate : privateKeyCertificate.getCertificates()) { final Element certificateElement = new Element(ELEMENT_NAME_CERTIFICATE); certificateElement.setText(X509Utils.certificateToBase64(certificate)); valueElement.addContent(certificateElement); } } { final Element keyElement = new Element(ELEMENT_NAME_KEY); final String b64EncodedKey = StringUtil.base64Encode(privateKeyCertificate.getKey().getEncoded()); final String encryptedKey = SecureEngine.encryptToString(b64EncodedKey, key, PwmBlockAlgorithm.CONFIG); keyElement.setText(encryptedKey); valueElement.addContent(keyElement); } } catch (Exception e) { valueElement.addContent(""); throw new RuntimeException("missing required AES and SHA1 libraries, or other crypto fault: " + e.getMessage()); } } return Collections.singletonList(valueElement); } public String toDebugString(final Locale locale) { if (privateKeyCertificate != null) { return "PrivateKeyCertificate: key=" + JsonUtil.serializeMap(X509Utils.makeDebugInfoMap(privateKeyCertificate.getKey())) + ", certificates=" + JsonUtil.serializeCollection(X509Utils.makeDebugInfoMap(privateKeyCertificate.getCertificates())); } return ""; } public Map<String,Object> toInfoMap(final boolean includeDetail) { if (privateKeyCertificate == null) { return null; } final X509Utils.DebugInfoFlag[] flags = includeDetail ? new X509Utils.DebugInfoFlag[]{X509Utils.DebugInfoFlag.IncludeCertificateDetail} : null; final Map<String,Object> returnMap = new LinkedHashMap<>(); returnMap.put("certificates", X509Utils.makeDebugInfoMap(privateKeyCertificate.getCertificates(), flags)); final Map<String,Object> privateKeyInfo = new LinkedHashMap<>(); privateKeyInfo.put("algorithm", privateKeyCertificate.getKey().getAlgorithm()); privateKeyInfo.put("format", privateKeyCertificate.getKey().getFormat()); returnMap.put("key", privateKeyInfo); return returnMap; } @Override public Serializable toDebugJsonObject(final Locale locale) { return (Serializable)toInfoMap(false); } }