Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/xml/crypto/dsig/X509KeySelector.java
38853 views
/*1* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.InputStream;24import java.io.IOException;25import java.security.Key;26import java.security.KeyStore;27import java.security.KeyStoreException;28import java.security.PublicKey;29import java.security.cert.Certificate;30import java.security.cert.CertificateFactory;31import java.security.cert.CertSelector;32import java.security.cert.X509Certificate;33import java.security.cert.X509CertSelector;34import java.util.*;35import javax.security.auth.x500.X500Principal;36import javax.xml.crypto.*;37import javax.xml.crypto.dsig.*;38import javax.xml.crypto.dom.*;39import javax.xml.crypto.dsig.keyinfo.*;4041import org.jcp.xml.dsig.internal.dom.DOMRetrievalMethod;4243/**44* A <code>KeySelector</code> that returns {@link PublicKey}s. If the45* selector is created as trusted, it only returns public keys of trusted46* {@link X509Certificate}s stored in a {@link KeyStore}. Otherwise, it47* returns trusted or untrusted public keys (it doesn't care as long48* as it finds one).49*50* <p>This <code>KeySelector</code> uses the specified <code>KeyStore</code>51* to find a trusted <code>X509Certificate</code> that matches information52* specified in the {@link KeyInfo} passed to the {@link #select} method.53* The public key from the first match is returned. If no match,54* <code>null</code> is returned. See the <code>select</code> method for more55* information.56*57* @author Sean Mullan58*/59class X509KeySelector extends KeySelector {6061private KeyStore ks;62private boolean trusted = true;6364/**65* Creates a trusted <code>X509KeySelector</code>.66*67* @param keyStore the keystore68* @throws KeyStoreException if the keystore has not been initialized69* @throws NullPointerException if <code>keyStore</code> is70* <code>null</code>71*/72X509KeySelector(KeyStore keyStore) throws KeyStoreException {73this(keyStore, true);74}7576X509KeySelector(KeyStore keyStore, boolean trusted)77throws KeyStoreException {78if (keyStore == null) {79throw new NullPointerException("keyStore is null");80}81this.trusted = trusted;82this.ks = keyStore;83// test to see if KeyStore has been initialized84this.ks.size();85}8687/**88* Finds a key from the keystore satisfying the specified constraints.89*90* <p>This method compares data contained in {@link KeyInfo} entries91* with information stored in the <code>KeyStore</code>. The implementation92* iterates over the KeyInfo types and returns the first {@link PublicKey}93* of an X509Certificate in the keystore that is compatible with the94* specified AlgorithmMethod according to the following rules for each95* keyinfo type:96*97* X509Data X509Certificate: if it contains a <code>KeyUsage</code>98* extension that asserts the <code>digitalSignature</code> bit and99* matches an <code>X509Certificate</code> in the <code>KeyStore</code>.100* X509Data X509IssuerSerial: if the serial number and issuer DN match an101* <code>X509Certificate</code> in the <code>KeyStore</code>.102* X509Data X509SubjectName: if the subject DN matches an103* <code>X509Certificate</code> in the <code>KeyStore</code>.104* X509Data X509SKI: if the subject key identifier matches an105* <code>X509Certificate</code> in the <code>KeyStore</code>.106* KeyName: if the keyname matches an alias in the <code>KeyStore</code>.107* RetrievalMethod: supports rawX509Certificate and X509Data types. If108* rawX509Certificate type, it must match an <code>X509Certificate</code>109* in the <code>KeyStore</code>.110*111* @param keyInfo a <code>KeyInfo</code> (may be <code>null</code>)112* @param purpose the key's purpose113* @param method the algorithm method that this key is to be used for.114* Only keys that are compatible with the algorithm and meet the115* constraints of the specified algorithm should be returned.116* @param an <code>XMLCryptoContext</code> that may contain additional117* useful information for finding an appropriate key118* @return a key selector result119* @throws KeySelectorException if an exceptional condition occurs while120* attempting to find a key. Note that an inability to find a key is not121* considered an exception (<code>null</code> should be122* returned in that case). However, an error condition (ex: network123* communications failure) that prevented the <code>KeySelector</code>124* from finding a potential key should be considered an exception.125* @throws ClassCastException if the data type of <code>method</code>126* is not supported by this key selector127*/128public KeySelectorResult select(KeyInfo keyInfo,129KeySelector.Purpose purpose, AlgorithmMethod method,130XMLCryptoContext context) throws KeySelectorException {131132SignatureMethod sm = (SignatureMethod) method;133134try {135// return null if keyinfo is null or keystore is empty136if (keyInfo == null || ks.size() == 0) {137return new SimpleKeySelectorResult(null);138}139140// Iterate through KeyInfo types141Iterator i = keyInfo.getContent().iterator();142while (i.hasNext()) {143XMLStructure kiType = (XMLStructure) i.next();144// check X509Data145if (kiType instanceof X509Data) {146X509Data xd = (X509Data) kiType;147KeySelectorResult ksr = x509DataSelect(xd, sm);148if (ksr != null) {149return ksr;150}151// check KeyName152} else if (kiType instanceof KeyName) {153KeyName kn = (KeyName) kiType;154Certificate cert = ks.getCertificate(kn.getName());155if (cert != null && algEquals(sm.getAlgorithm(),156cert.getPublicKey().getAlgorithm())) {157return new SimpleKeySelectorResult(cert.getPublicKey());158}159// check RetrievalMethod160} else if (kiType instanceof RetrievalMethod) {161RetrievalMethod rm = (RetrievalMethod) kiType;162try {163KeySelectorResult ksr = null;164if (rm.getType().equals165(X509Data.RAW_X509_CERTIFICATE_TYPE)) {166OctetStreamData data = (OctetStreamData)167rm.dereference(context);168CertificateFactory cf =169CertificateFactory.getInstance("X.509");170X509Certificate cert = (X509Certificate)171cf.generateCertificate(data.getOctetStream());172ksr = certSelect(cert, sm);173} else if (rm.getType().equals(X509Data.TYPE)) {174X509Data xd = (X509Data) ((DOMRetrievalMethod) rm).175dereferenceAsXMLStructure(context);176ksr = x509DataSelect(xd, sm);177} else {178// skip; keyinfo type is not supported179continue;180}181if (ksr != null) {182return ksr;183}184} catch (Exception e) {185throw new KeySelectorException(e);186}187}188}189} catch (KeyStoreException kse) {190// throw exception if keystore is uninitialized191throw new KeySelectorException(kse);192}193194// return null since no match could be found195return new SimpleKeySelectorResult(null);196}197198/**199* Searches the specified keystore for a certificate that matches the200* criteria specified in the CertSelector.201*202* @return a KeySelectorResult containing the cert's public key if there203* is a match; otherwise null204*/205private KeySelectorResult keyStoreSelect(CertSelector cs)206throws KeyStoreException {207Enumeration<String> aliases = ks.aliases();208while (aliases.hasMoreElements()) {209String alias = aliases.nextElement();210Certificate cert = ks.getCertificate(alias);211if (cert != null && cs.match(cert)) {212return new SimpleKeySelectorResult(cert.getPublicKey());213}214}215return null;216}217218/**219* Searches the specified keystore for a certificate that matches the220* specified X509Certificate and contains a public key that is compatible221* with the specified SignatureMethod.222*223* @return a KeySelectorResult containing the cert's public key if there224* is a match; otherwise null225*/226private KeySelectorResult certSelect(X509Certificate xcert,227SignatureMethod sm) throws KeyStoreException {228// skip non-signer certs229boolean[] keyUsage = xcert.getKeyUsage();230if (keyUsage != null && keyUsage[0] == false) {231return null;232}233String alias = ks.getCertificateAlias(xcert);234if (alias != null) {235PublicKey pk = ks.getCertificate(alias).getPublicKey();236// make sure algorithm is compatible with method237if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {238return new SimpleKeySelectorResult(pk);239}240}241return null;242}243244/**245* Returns an OID of a public-key algorithm compatible with the specified246* signature algorithm URI.247*/248private String getPKAlgorithmOID(String algURI) {249if (algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {250return "1.2.840.10040.4.1";251} else if (algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {252return "1.2.840.113549.1.1";253} else {254return null;255}256}257258/**259* A simple KeySelectorResult containing a public key.260*/261private static class SimpleKeySelectorResult implements KeySelectorResult {262private final Key key;263SimpleKeySelectorResult(Key key) { this.key = key; }264public Key getKey() { return key; }265}266267/**268* Checks if a JCA/JCE public key algorithm name is compatible with269* the specified signature algorithm URI.270*/271//@@@FIXME: this should also work for key types other than DSA/RSA272private boolean algEquals(String algURI, String algName) {273if (algName.equalsIgnoreCase("DSA") &&274algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {275return true;276} else if (algName.equalsIgnoreCase("RSA") &&277algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {278return true;279} else {280return false;281}282}283284/**285* Searches the specified keystore for a certificate that matches an286* entry of the specified X509Data and contains a public key that is287* compatible with the specified SignatureMethod.288*289* @return a KeySelectorResult containing the cert's public key if there290* is a match; otherwise null291*/292private KeySelectorResult x509DataSelect(X509Data xd, SignatureMethod sm)293throws KeyStoreException, KeySelectorException {294295// convert signature algorithm to compatible public-key alg OID296String algOID = getPKAlgorithmOID(sm.getAlgorithm());297X509CertSelector subjectcs = new X509CertSelector();298try {299subjectcs.setSubjectPublicKeyAlgID(algOID);300} catch (IOException ioe) {301throw new KeySelectorException(ioe);302}303Collection<X509Certificate> certs = new ArrayList<>();304305Iterator xi = xd.getContent().iterator();306while (xi.hasNext()) {307Object o = xi.next();308// check X509IssuerSerial309if (o instanceof X509IssuerSerial) {310X509IssuerSerial xis = (X509IssuerSerial) o;311try {312subjectcs.setSerialNumber(xis.getSerialNumber());313String issuer = new X500Principal(xis.getIssuerName()).getName();314// strip off newline315if (issuer.endsWith("\n")) {316issuer = new String317(issuer.toCharArray(), 0, issuer.length()-1);318}319subjectcs.setIssuer(issuer);320} catch (IOException ioe) {321throw new KeySelectorException(ioe);322}323// check X509SubjectName324} else if (o instanceof String) {325String sn = (String) o;326try {327String subject = new X500Principal(sn).getName();328// strip off newline329if (subject.endsWith("\n")) {330subject = new String331(subject.toCharArray(), 0, subject.length()-1);332}333subjectcs.setSubject(subject);334} catch (IOException ioe) {335throw new KeySelectorException(ioe);336}337// check X509SKI338} else if (o instanceof byte[]) {339byte[] ski = (byte[]) o;340// DER-encode ski - required by X509CertSelector341byte[] encodedSki = new byte[ski.length+2];342encodedSki[0] = 0x04; // OCTET STRING tag value343encodedSki[1] = (byte) ski.length; // length344System.arraycopy(ski, 0, encodedSki, 2, ski.length);345subjectcs.setSubjectKeyIdentifier(encodedSki);346} else if (o instanceof X509Certificate) {347certs.add((X509Certificate)o);348// check X509CRL349// not supported: should use CertPath API350} else {351// skip all other entries352continue;353}354}355KeySelectorResult ksr = keyStoreSelect(subjectcs);356if (ksr != null) {357return ksr;358}359if (!certs.isEmpty() && !trusted) {360// try to find public key in certs in X509Data361for (X509Certificate cert : certs) {362if (subjectcs.match(cert)) {363return new SimpleKeySelectorResult(cert.getPublicKey());364}365}366}367return null;368}369}370371372