Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/xml/crypto/dsig/KeySelectors.java
38853 views
/*1* Copyright (c) 2005, 2018, 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.*;24import java.security.Key;25import java.security.KeyException;26import java.security.PublicKey;27import java.security.cert.*;28import java.util.*;29import javax.crypto.SecretKey;30import javax.xml.crypto.*;31import javax.xml.crypto.dsig.*;32import javax.xml.crypto.dsig.keyinfo.*;33import sun.security.util.DerValue;34import sun.security.x509.X500Name;3536/**37* This is a class which supplies several KeySelector implementations38*/39class KeySelectors {4041/**42* KeySelector which would always return the secret key specified in its43* constructor.44*/45static class SecretKeySelector extends KeySelector {46private SecretKey key;47SecretKeySelector(byte[] bytes) {48key = wrapBytes(bytes);49}50SecretKeySelector(SecretKey key) {51this.key = key;52}5354public KeySelectorResult select(KeyInfo ki,55KeySelector.Purpose purpose,56AlgorithmMethod method,57XMLCryptoContext context)58throws KeySelectorException {59return new SimpleKSResult(key);60}6162private SecretKey wrapBytes(final byte[] bytes) {63return new SecretKey() {64public String getFormat() {65return "RAW";66}6768public String getAlgorithm() {69return "Secret key";70}7172public byte[] getEncoded() {73return bytes.clone();74}75};76}77}7879/**80* KeySelector which would retrieve the X509Certificate out of the81* KeyInfo element and return the public key.82* NOTE: If there is an X509CRL in the KeyInfo element, then revoked83* certificate will be ignored.84*/85static class RawX509KeySelector extends KeySelector {8687public KeySelectorResult select(KeyInfo keyInfo,88KeySelector.Purpose purpose,89AlgorithmMethod method,90XMLCryptoContext context)91throws KeySelectorException {92if (keyInfo == null) {93throw new KeySelectorException("Null KeyInfo object!");94}95// search for X509Data in keyinfo96Iterator iter = keyInfo.getContent().iterator();97while (iter.hasNext()) {98XMLStructure kiType = (XMLStructure) iter.next();99if (kiType instanceof X509Data) {100X509Data xd = (X509Data) kiType;101Object[] entries = xd.getContent().toArray();102X509CRL crl = null;103// Looking for CRL before finding certificates104for (int i = 0; (i<entries.length&&crl != null); i++) {105if (entries[i] instanceof X509CRL) {106crl = (X509CRL) entries[i];107}108}109Iterator xi = xd.getContent().iterator();110boolean hasCRL = false;111while (xi.hasNext()) {112Object o = xi.next();113// skip non-X509Certificate entries114if (o instanceof X509Certificate) {115if ((purpose != KeySelector.Purpose.VERIFY) &&116(crl != null) &&117crl.isRevoked((X509Certificate)o)) {118continue;119} else {120return new SimpleKSResult121(((X509Certificate)o).getPublicKey());122}123}124}125}126}127throw new KeySelectorException("No X509Certificate found!");128}129}130131/**132* KeySelector which would retrieve the public key out of the133* KeyValue element and return it.134* NOTE: If the key algorithm doesn't match signature algorithm,135* then the public key will be ignored.136*/137static class KeyValueKeySelector extends KeySelector {138public KeySelectorResult select(KeyInfo keyInfo,139KeySelector.Purpose purpose,140AlgorithmMethod method,141XMLCryptoContext context)142throws KeySelectorException {143if (keyInfo == null) {144throw new KeySelectorException("Null KeyInfo object!");145}146SignatureMethod sm = (SignatureMethod) method;147List list = keyInfo.getContent();148149for (int i = 0; i < list.size(); i++) {150XMLStructure xmlStructure = (XMLStructure) list.get(i);151if (xmlStructure instanceof KeyValue) {152PublicKey pk = null;153try {154pk = ((KeyValue)xmlStructure).getPublicKey();155} catch (KeyException ke) {156throw new KeySelectorException(ke);157}158// make sure algorithm is compatible with method159if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {160return new SimpleKSResult(pk);161}162}163}164throw new KeySelectorException("No KeyValue element found!");165}166167static boolean algEquals(String algURI, String algName) {168algName = algName.toUpperCase(Locale.ROOT);169return algName.equals("DSA") && algURI.contains("#dsa-")170|| algName.equals("RSA")171&& (algURI.contains("#rsa-") || algURI.contains("-rsa-MGF1"))172|| algName.equals("EC") && algURI.contains("#ecdsa-");173}174}175176/**177* KeySelector which would perform special lookup as documented178* by the ie/baltimore/merlin-examples testcases and return the179* matching public key.180*/181static class CollectionKeySelector extends KeySelector {182private CertificateFactory cf;183private File certDir;184private Vector<X509Certificate> certs;185private static final int MATCH_SUBJECT = 0;186private static final int MATCH_ISSUER = 1;187private static final int MATCH_SERIAL = 2;188private static final int MATCH_SUBJECT_KEY_ID = 3;189private static final int MATCH_CERTIFICATE = 4;190191CollectionKeySelector(File dir) {192certDir = dir;193try {194cf = CertificateFactory.getInstance("X509");195} catch (CertificateException ex) {196// not going to happen197}198certs = new Vector<X509Certificate>();199File[] files = new File(certDir, "certs").listFiles();200for (int i = 0; i < files.length; i++) {201try (FileInputStream fis = new FileInputStream(files[i])) {202certs.add((X509Certificate)cf.generateCertificate(fis));203} catch (Exception ex) { }204}205}206207Vector<X509Certificate> match(int matchType, Object value,208Vector<X509Certificate> pool) {209Vector<X509Certificate> matchResult = new Vector<>();210for (int j=0; j < pool.size(); j++) {211X509Certificate c = pool.get(j);212switch (matchType) {213case MATCH_SUBJECT:214try {215if (c.getSubjectDN().equals(new X500Name((String)value))) {216matchResult.add(c);217}218} catch (IOException ioe) { }219break;220case MATCH_ISSUER:221try {222if (c.getIssuerDN().equals(new X500Name((String)value))) {223matchResult.add(c);224}225} catch (IOException ioe) { }226break;227case MATCH_SERIAL:228if (c.getSerialNumber().equals(value)) {229matchResult.add(c);230}231232break;233case MATCH_SUBJECT_KEY_ID:234byte[] extension = c.getExtensionValue("2.5.29.14");235if (extension != null) {236try {237DerValue derValue = new DerValue(extension);238DerValue derValue2 = new DerValue(derValue.getOctetString());239byte[] extVal = derValue2.getOctetString();240241if (Arrays.equals(extVal, (byte[]) value)) {242matchResult.add(c);243}244} catch (IOException ex) { }245}246break;247case MATCH_CERTIFICATE:248if (c.equals(value)) {249matchResult.add(c);250}251break;252}253}254return matchResult;255}256257public KeySelectorResult select(KeyInfo keyInfo,258KeySelector.Purpose purpose,259AlgorithmMethod method,260XMLCryptoContext context)261throws KeySelectorException {262if (keyInfo == null) {263throw new KeySelectorException("Null KeyInfo object!");264}265Iterator iter = keyInfo.getContent().iterator();266while (iter.hasNext()) {267XMLStructure xmlStructure = (XMLStructure) iter.next();268try {269if (xmlStructure instanceof KeyName) {270String name = ((KeyName)xmlStructure).getName();271PublicKey pk = null;272File certFile = new File(new File(certDir, "certs"),273name.toLowerCase() + ".crt");274try (FileInputStream fis = new FileInputStream(certFile)) {275// Lookup the public key using the key name 'Xxx',276// i.e. the public key is in "certs/xxx.crt".277X509Certificate cert = (X509Certificate)278cf.generateCertificate(fis);279pk = cert.getPublicKey();280} catch (FileNotFoundException e) {281// assume KeyName contains subject DN and search282// collection of certs for match283Vector<X509Certificate> result =284match(MATCH_SUBJECT, name, certs);285int numOfMatches = (result==null? 0:result.size());286if (numOfMatches != 1) {287throw new KeySelectorException288((numOfMatches==0?"No":"More than one") +289" match found");290}291pk = result.get(0).getPublicKey();292}293return new SimpleKSResult(pk);294} else if (xmlStructure instanceof RetrievalMethod) {295// Lookup the public key using the retrievel method.296// NOTE: only X509Certificate type is supported.297RetrievalMethod rm = (RetrievalMethod) xmlStructure;298String type = rm.getType();299if (type.equals(X509Data.RAW_X509_CERTIFICATE_TYPE)) {300String uri = rm.getURI();301try (FileInputStream fis =302new FileInputStream(new File(certDir, uri))) {303X509Certificate cert = (X509Certificate)304cf.generateCertificate(fis);305return new SimpleKSResult(cert.getPublicKey());306}307} else {308throw new KeySelectorException309("Unsupported RetrievalMethod type");310}311} else if (xmlStructure instanceof X509Data) {312List content = ((X509Data)xmlStructure).getContent();313int size = content.size();314Vector<X509Certificate> result = null;315// Lookup the public key using the information316// specified in X509Data element, i.e. searching317// over the collection of certificate files under318// "certs" subdirectory and return those match.319for (int k = 0; k<size; k++) {320Object obj = content.get(k);321if (obj instanceof String) {322result = match(MATCH_SUBJECT, obj, certs);323} else if (obj instanceof byte[]) {324result = match(MATCH_SUBJECT_KEY_ID, obj,325certs);326} else if (obj instanceof X509Certificate) {327result = match(MATCH_CERTIFICATE, obj, certs);328} else if (obj instanceof X509IssuerSerial) {329X509IssuerSerial is = (X509IssuerSerial) obj;330result = match(MATCH_SERIAL,331is.getSerialNumber(), certs);332result = match(MATCH_ISSUER,333is.getIssuerName(), result);334} else {335throw new KeySelectorException("Unsupported X509Data: " + obj);336}337}338int numOfMatches = (result==null? 0:result.size());339if (numOfMatches != 1) {340throw new KeySelectorException341((numOfMatches==0?"No":"More than one") +342" match found");343}344return new SimpleKSResult(result.get(0).getPublicKey());345}346} catch (Exception ex) {347throw new KeySelectorException(ex);348}349}350throw new KeySelectorException("No matching key found!");351}352}353354static class ByteUtil {355356private static String mapping = "0123456789ABCDEF";357private static int numBytesPerRow = 6;358359private static String getHex(byte value) {360int low = value & 0x0f;361int high = ((value >> 4) & 0x0f);362char[] res = new char[2];363res[0] = mapping.charAt(high);364res[1] = mapping.charAt(low);365return new String(res);366}367368static String dumpArray(byte[] in) {369int numDumped = 0;370StringBuffer buf = new StringBuffer(512);371buf.append("{");372for (int i=0;i<(in.length/numBytesPerRow); i++) {373for (int j=0; j<(numBytesPerRow); j++) {374buf.append("(byte)0x" + getHex(in[i*numBytesPerRow+j]) +375", ");376}377numDumped += numBytesPerRow;378}379while (numDumped < in.length) {380buf.append("(byte)0x" + getHex(in[numDumped]) + " ");381numDumped += 1;382}383buf.append("}");384return buf.toString();385}386}387}388389class SimpleKSResult implements KeySelectorResult {390private final Key key;391392SimpleKSResult(Key key) { this.key = key; }393394public Key getKey() { return key; }395}396397398