Path: blob/master/src/java.base/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java
41159 views
/*1* Copyright (c) 1997, 2009, 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.x509;2627import java.io.IOException;28import java.io.OutputStream;29import java.util.Enumeration;3031import sun.security.util.*;3233/**34* This class represents the Authority Key Identifier Extension.35*36* <p>The authority key identifier extension provides a means of37* identifying the particular public key used to sign a certificate.38* This extension would be used where an issuer has multiple signing39* keys (either due to multiple concurrent key pairs or due to40* changeover).41* <p>42* The ASN.1 syntax for this is:43* <pre>44* AuthorityKeyIdentifier ::= SEQUENCE {45* keyIdentifier [0] KeyIdentifier OPTIONAL,46* authorityCertIssuer [1] GeneralNames OPTIONAL,47* authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL48* }49* KeyIdentifier ::= OCTET STRING50* </pre>51* @author Amit Kapoor52* @author Hemma Prafullchandra53* @see Extension54* @see CertAttrSet55*/56public class AuthorityKeyIdentifierExtension extends Extension57implements CertAttrSet<String> {58/**59* Identifier for this attribute, to be used with the60* get, set, delete methods of Certificate, x509 type.61*/62public static final String IDENT =63"x509.info.extensions.AuthorityKeyIdentifier";64/**65* Attribute names.66*/67public static final String NAME = "AuthorityKeyIdentifier";68public static final String KEY_ID = "key_id";69public static final String AUTH_NAME = "auth_name";70public static final String SERIAL_NUMBER = "serial_number";7172// Private data members73private static final byte TAG_ID = 0;74private static final byte TAG_NAMES = 1;75private static final byte TAG_SERIAL_NUM = 2;7677private KeyIdentifier id = null;78private GeneralNames names = null;79private SerialNumber serialNum = null;8081// Encode only the extension value82private void encodeThis() throws IOException {83if (id == null && names == null && serialNum == null) {84this.extensionValue = null;85return;86}87DerOutputStream seq = new DerOutputStream();88DerOutputStream tmp = new DerOutputStream();89if (id != null) {90DerOutputStream tmp1 = new DerOutputStream();91id.encode(tmp1);92tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,93false, TAG_ID), tmp1);94}95try {96if (names != null) {97DerOutputStream tmp1 = new DerOutputStream();98names.encode(tmp1);99tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,100true, TAG_NAMES), tmp1);101}102} catch (Exception e) {103throw new IOException(e.toString());104}105if (serialNum != null) {106DerOutputStream tmp1 = new DerOutputStream();107serialNum.encode(tmp1);108tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,109false, TAG_SERIAL_NUM), tmp1);110}111seq.write(DerValue.tag_Sequence, tmp);112this.extensionValue = seq.toByteArray();113}114115/**116* The default constructor for this extension. Null parameters make117* the element optional (not present).118*119* @param kid the KeyIdentifier associated with this extension.120* @param names the GeneralNames associated with this extension121* @param sn the CertificateSerialNumber associated with122* this extension.123* @exception IOException on error.124*/125public AuthorityKeyIdentifierExtension(KeyIdentifier kid, GeneralNames names,126SerialNumber sn)127throws IOException {128this.id = kid;129this.names = names;130this.serialNum = sn;131132this.extensionId = PKIXExtensions.AuthorityKey_Id;133this.critical = false;134encodeThis();135}136137/**138* Create the extension from the passed DER encoded value of the same.139*140* @param critical true if the extension is to be treated as critical.141* @param value an array of DER encoded bytes of the actual value.142* @exception ClassCastException if value is not an array of bytes143* @exception IOException on error.144*/145public AuthorityKeyIdentifierExtension(Boolean critical, Object value)146throws IOException {147this.extensionId = PKIXExtensions.AuthorityKey_Id;148this.critical = critical.booleanValue();149150this.extensionValue = (byte[]) value;151DerValue val = new DerValue(this.extensionValue);152if (val.tag != DerValue.tag_Sequence) {153throw new IOException("Invalid encoding for " +154"AuthorityKeyIdentifierExtension.");155}156157// Note that all the fields in AuthorityKeyIdentifier are defined as158// being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting159// in val.data being null.160while ((val.data != null) && (val.data.available() != 0)) {161DerValue opt = val.data.getDerValue();162163// NB. this is always encoded with the IMPLICIT tag164// The checks only make sense if we assume implicit tagging,165// with explicit tagging the form is always constructed.166if (opt.isContextSpecific(TAG_ID) && !opt.isConstructed()) {167if (id != null)168throw new IOException("Duplicate KeyIdentifier in " +169"AuthorityKeyIdentifier.");170opt.resetTag(DerValue.tag_OctetString);171id = new KeyIdentifier(opt);172173} else if (opt.isContextSpecific(TAG_NAMES) &&174opt.isConstructed()) {175if (names != null)176throw new IOException("Duplicate GeneralNames in " +177"AuthorityKeyIdentifier.");178opt.resetTag(DerValue.tag_Sequence);179names = new GeneralNames(opt);180181} else if (opt.isContextSpecific(TAG_SERIAL_NUM) &&182!opt.isConstructed()) {183if (serialNum != null)184throw new IOException("Duplicate SerialNumber in " +185"AuthorityKeyIdentifier.");186opt.resetTag(DerValue.tag_Integer);187serialNum = new SerialNumber(opt);188} else189throw new IOException("Invalid encoding of " +190"AuthorityKeyIdentifierExtension.");191}192}193194/**195* Return the object as a string.196*/197public String toString() {198StringBuilder sb = new StringBuilder();199sb.append(super.toString())200.append("AuthorityKeyIdentifier [\n");201if (id != null) {202sb.append(id); // id already has a newline203}204if (names != null) {205sb.append(names).append('\n');206}207if (serialNum != null) {208sb.append(serialNum).append('\n');209}210sb.append("]\n");211return sb.toString();212}213214/**215* Write the extension to the OutputStream.216*217* @param out the OutputStream to write the extension to.218* @exception IOException on error.219*/220public void encode(OutputStream out) throws IOException {221DerOutputStream tmp = new DerOutputStream();222if (this.extensionValue == null) {223extensionId = PKIXExtensions.AuthorityKey_Id;224critical = false;225encodeThis();226}227super.encode(tmp);228out.write(tmp.toByteArray());229}230231/**232* Set the attribute value.233*/234public void set(String name, Object obj) throws IOException {235if (name.equalsIgnoreCase(KEY_ID)) {236if (!(obj instanceof KeyIdentifier)) {237throw new IOException("Attribute value should be of " +238"type KeyIdentifier.");239}240id = (KeyIdentifier)obj;241} else if (name.equalsIgnoreCase(AUTH_NAME)) {242if (!(obj instanceof GeneralNames)) {243throw new IOException("Attribute value should be of " +244"type GeneralNames.");245}246names = (GeneralNames)obj;247} else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {248if (!(obj instanceof SerialNumber)) {249throw new IOException("Attribute value should be of " +250"type SerialNumber.");251}252serialNum = (SerialNumber)obj;253} else {254throw new IOException("Attribute name not recognized by " +255"CertAttrSet:AuthorityKeyIdentifier.");256}257encodeThis();258}259260/**261* Get the attribute value.262*/263public Object get(String name) throws IOException {264if (name.equalsIgnoreCase(KEY_ID)) {265return (id);266} else if (name.equalsIgnoreCase(AUTH_NAME)) {267return (names);268} else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {269return (serialNum);270} else {271throw new IOException("Attribute name not recognized by " +272"CertAttrSet:AuthorityKeyIdentifier.");273}274}275276/**277* Delete the attribute value.278*/279public void delete(String name) throws IOException {280if (name.equalsIgnoreCase(KEY_ID)) {281id = null;282} else if (name.equalsIgnoreCase(AUTH_NAME)) {283names = null;284} else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {285serialNum = null;286} else {287throw new IOException("Attribute name not recognized by " +288"CertAttrSet:AuthorityKeyIdentifier.");289}290encodeThis();291}292293/**294* Return an enumeration of names of attributes existing within this295* attribute.296*/297public Enumeration<String> getElements() {298AttributeNameEnumeration elements = new AttributeNameEnumeration();299elements.addElement(KEY_ID);300elements.addElement(AUTH_NAME);301elements.addElement(SERIAL_NUMBER);302303return (elements.elements());304}305306/**307* Return the name of this attribute.308*/309public String getName() {310return (NAME);311}312313/**314* Return the encoded key identifier, or null if not specified.315*/316public byte[] getEncodedKeyIdentifier() throws IOException {317if (id != null) {318DerOutputStream derOut = new DerOutputStream();319id.encode(derOut);320return derOut.toByteArray();321}322return null;323}324}325326327