Path: blob/master/src/java.base/share/classes/sun/security/provider/certpath/ResponderId.java
41161 views
/*1* Copyright (c) 2015, 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. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider.certpath;2627import java.util.Arrays;28import java.io.IOException;29import java.security.PublicKey;30import javax.security.auth.x500.X500Principal;31import sun.security.x509.KeyIdentifier;32import sun.security.util.DerValue;3334/**35* Class for ResponderId entities as described in RFC6960. ResponderId objects36* are used to uniquely identify OCSP responders.37* <p>38* The RFC 6960 defines a ResponderID structure as:39* <pre>40* ResponderID ::= CHOICE {41* byName [1] Name,42* byKey [2] KeyHash }43*44* KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key45* (excluding the tag and length fields)46*47* Name is defined in RFC 5280.48* </pre>49*50* @see ResponderId.Type51* @since 952*/53public final class ResponderId {5455/**56* A {@code ResponderId} enumeration describing the accepted forms for a57* {@code ResponderId}.58*59* @see ResponderId60* @since 961*/62public static enum Type {63/**64* A BY_NAME {@code ResponderId} will be built from a subject name,65* either as an {@code X500Principal} or a DER-encoded byte array.66*/67BY_NAME(1, "byName"),6869/**70* A BY_KEY {@code ResponderId} will be built from a public key71* identifier, either derived from a {@code PublicKey} or directly72* from a DER-encoded byte array containing the key identifier.73*/74BY_KEY(2, "byKey");7576private final int tagNumber;77private final String ridTypeName;7879private Type(int value, String name) {80this.tagNumber = value;81this.ridTypeName = name;82}8384public int value() {85return tagNumber;86}8788@Override89public String toString() {90return ridTypeName;91}92}9394private Type type;95private X500Principal responderName;96private KeyIdentifier responderKeyId;97private byte[] encodedRid;9899/**100* Constructs a {@code ResponderId} object using an {@code X500Principal}.101* When encoded in DER this object will use the BY_NAME option.102*103* @param subjectName the subject name of the certificate used104* to sign OCSP responses.105*106* @throws IOException if the internal DER-encoding of the107* {@code X500Principal} fails.108*/109public ResponderId(X500Principal subjectName) throws IOException {110responderName = subjectName;111responderKeyId = null;112encodedRid = principalToBytes();113type = Type.BY_NAME;114}115116/**117* Constructs a {@code ResponderId} object using a {@code PublicKey}.118* When encoded in DER this object will use the byKey option, a119* SHA-1 hash of the responder's public key.120*121* @param pubKey the OCSP responder's public key122*123* @throws IOException if the internal DER-encoding of the124* {@code KeyIdentifier} fails.125*/126public ResponderId(PublicKey pubKey) throws IOException {127responderKeyId = new KeyIdentifier(pubKey);128responderName = null;129encodedRid = keyIdToBytes();130type = Type.BY_KEY;131}132133/**134* Constructs a {@code ResponderId} object from its DER-encoding.135*136* @param encodedData the DER-encoded bytes137*138* @throws IOException if the encodedData is not properly DER encoded139*/140public ResponderId(byte[] encodedData) throws IOException {141DerValue outer = new DerValue(encodedData);142143if (outer.isContextSpecific((byte)Type.BY_NAME.value())144&& outer.isConstructed()) {145// Use the X500Principal constructor as a way to sanity146// check the incoming data.147responderName = new X500Principal(outer.getDataBytes());148encodedRid = principalToBytes();149type = Type.BY_NAME;150} else if (outer.isContextSpecific((byte)Type.BY_KEY.value())151&& outer.isConstructed()) {152// Use the KeyIdentifier constructor as a way to sanity153// check the incoming data.154responderKeyId =155new KeyIdentifier(new DerValue(outer.getDataBytes()));156encodedRid = keyIdToBytes();157type = Type.BY_KEY;158} else {159throw new IOException("Invalid ResponderId content");160}161}162163/**164* Encode a {@code ResponderId} in DER form165*166* @return a byte array containing the DER-encoded representation for this167* {@code ResponderId}168*/169public byte[] getEncoded() {170return encodedRid.clone();171}172173/**174* Return the type of {@ResponderId}175*176* @return a number corresponding to the context-specific tag number177* used in the DER-encoding for a {@code ResponderId}178*/179public ResponderId.Type getType() {180return type;181}182183/**184* Get the length of the encoded {@code ResponderId} (including the tag and185* length of the explicit tagging from the outer ASN.1 CHOICE).186*187* @return the length of the encoded {@code ResponderId}188*/189public int length() {190return encodedRid.length;191}192193/**194* Obtain the underlying {@code X500Principal} from a {@code ResponderId}195*196* @return the {@code X500Principal} for this {@code ResponderId} if it197* is a BY_NAME variant. If the {@code ResponderId} is a BY_KEY198* variant, this routine will return {@code null}.199*/200public X500Principal getResponderName() {201return responderName;202}203204/**205* Obtain the underlying key identifier from a {@code ResponderId}206*207* @return the {@code KeyIdentifier} for this {@code ResponderId} if it208* is a BY_KEY variant. If the {@code ResponderId} is a BY_NAME209* variant, this routine will return {@code null}.210*/211public KeyIdentifier getKeyIdentifier() {212return responderKeyId;213}214215/**216* Compares the specified object with this {@code ResponderId} for equality.217* A ResponderId will only be considered equivalent if both the type and218* data value are equal. Two ResponderIds initialized by name and219* key ID, respectively, will not be equal even if the220* ResponderId objects are created from the same source certificate.221*222* @param obj the object to be compared against223*224* @return true if the specified object is equal to this {@code Responderid}225*/226@Override227public boolean equals(Object obj) {228if (obj == null) {229return false;230}231232if (this == obj) {233return true;234}235236if (obj instanceof ResponderId) {237ResponderId respObj = (ResponderId)obj;238return Arrays.equals(encodedRid, respObj.getEncoded());239}240241return false;242}243244/**245* Returns the hash code value for this {@code ResponderId}246*247* @return the hash code value for this {@code ResponderId}248*/249@Override250public int hashCode() {251return Arrays.hashCode(encodedRid);252}253254/**255* Create a String representation of this {@code ResponderId}256*257* @return a String representation of this {@code ResponderId}258*/259@Override260public String toString() {261StringBuilder sb = new StringBuilder();262switch (type) {263case BY_NAME:264sb.append(type).append(": ").append(responderName);265break;266case BY_KEY:267sb.append(type).append(": ");268for (byte keyIdByte : responderKeyId.getIdentifier()) {269sb.append(String.format("%02X", keyIdByte));270}271break;272default:273sb.append("Unknown ResponderId Type: ").append(type);274}275return sb.toString();276}277278/**279* Convert the responderName data member into its DER-encoded form280*281* @return the DER encoding for a responder ID byName option, including282* explicit context-specific tagging.283*284* @throws IOException if any encoding error occurs285*/286private byte[] principalToBytes() throws IOException {287DerValue dv = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,288true, (byte)Type.BY_NAME.value()),289responderName.getEncoded());290return dv.toByteArray();291}292293/**294* Convert the responderKeyId data member into its DER-encoded form295*296* @return the DER encoding for a responder ID byKey option, including297* explicit context-specific tagging.298*299* @throws IOException if any encoding error occurs300*/301private byte[] keyIdToBytes() throws IOException {302// Place the KeyIdentifier bytes into an OCTET STRING303DerValue inner = new DerValue(DerValue.tag_OctetString,304responderKeyId.getIdentifier());305306// Mark the OCTET STRING-wrapped KeyIdentifier bytes307// as EXPLICIT CONTEXT 2308DerValue outer = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,309true, (byte)Type.BY_KEY.value()), inner.toByteArray());310311return outer.toByteArray();312}313314}315316317