Path: blob/master/src/java.base/share/classes/sun/security/x509/KeyUsageExtension.java
41159 views
/*1* Copyright (c) 1997, 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.x509;2627import java.io.IOException;28import java.io.OutputStream;29import java.util.Enumeration;3031import sun.security.util.*;3233/**34* Represent the Key Usage Extension.35*36* <p>This extension, if present, defines the purpose (e.g., encipherment,37* signature, certificate signing) of the key contained in the certificate.38* The usage restriction might be employed when a multipurpose key is to be39* restricted (e.g., when an RSA key should be used only for signing or only40* for key encipherment).41*42* @author Amit Kapoor43* @author Hemma Prafullchandra44* @see Extension45* @see CertAttrSet46*/47public class KeyUsageExtension extends Extension48implements CertAttrSet<String> {4950/**51* Identifier for this attribute, to be used with the52* get, set, delete methods of Certificate, x509 type.53*/54public static final String IDENT = "x509.info.extensions.KeyUsage";55/**56* Attribute names.57*/58public static final String NAME = "KeyUsage";59public static final String DIGITAL_SIGNATURE = "digital_signature";60public static final String NON_REPUDIATION = "non_repudiation";61public static final String KEY_ENCIPHERMENT = "key_encipherment";62public static final String DATA_ENCIPHERMENT = "data_encipherment";63public static final String KEY_AGREEMENT = "key_agreement";64public static final String KEY_CERTSIGN = "key_certsign";65public static final String CRL_SIGN = "crl_sign";66public static final String ENCIPHER_ONLY = "encipher_only";67public static final String DECIPHER_ONLY = "decipher_only";6869// Private data members70private boolean[] bitString;7172// Encode this extension value73private void encodeThis() throws IOException {74DerOutputStream os = new DerOutputStream();75os.putTruncatedUnalignedBitString(new BitArray(this.bitString));76this.extensionValue = os.toByteArray();77}7879/**80* Check if bit is set.81*82* @param position the position in the bit string to check.83*/84private boolean isSet(int position) {85return (position < bitString.length) &&86bitString[position];87}8889/**90* Set the bit at the specified position.91*/92private void set(int position, boolean val) {93// enlarge bitString if necessary94if (position >= bitString.length) {95boolean[] tmp = new boolean[position+1];96System.arraycopy(bitString, 0, tmp, 0, bitString.length);97bitString = tmp;98}99bitString[position] = val;100}101102/**103* Create a KeyUsageExtension with the passed bit settings. The criticality104* is set to true.105*106* @param bitString the bits to be set for the extension.107*/108public KeyUsageExtension(byte[] bitString) throws IOException {109this.bitString =110new BitArray(bitString.length*8,bitString).toBooleanArray();111this.extensionId = PKIXExtensions.KeyUsage_Id;112this.critical = true;113encodeThis();114}115116/**117* Create a KeyUsageExtension with the passed bit settings. The criticality118* is set to true.119*120* @param bitString the bits to be set for the extension.121*/122public KeyUsageExtension(boolean[] bitString) throws IOException {123this.bitString = bitString;124this.extensionId = PKIXExtensions.KeyUsage_Id;125this.critical = true;126encodeThis();127}128129/**130* Create a KeyUsageExtension with the passed bit settings. The criticality131* is set to true.132*133* @param bitString the bits to be set for the extension.134*/135public KeyUsageExtension(BitArray bitString) throws IOException {136this.bitString = bitString.toBooleanArray();137this.extensionId = PKIXExtensions.KeyUsage_Id;138this.critical = true;139encodeThis();140}141142/**143* Create the extension from the passed DER encoded value of the same.144* The DER encoded value may be wrapped in an OCTET STRING.145*146* @param critical true if the extension is to be treated as critical.147* @param value an array of DER encoded bytes of the actual value (possibly148* wrapped in an OCTET STRING).149* @exception ClassCastException if value is not an array of bytes150* @exception IOException on error.151*/152public KeyUsageExtension(Boolean critical, Object value)153throws IOException {154this.extensionId = PKIXExtensions.KeyUsage_Id;155this.critical = critical.booleanValue();156/*157* The following check should be activated again after158* the PKIX profiling work becomes standard and the check159* is not a barrier to interoperability !160* if (!this.critical) {161* throw new IOException("KeyUsageExtension not marked critical,"162* + " invalid profile.");163* }164*/165byte[] extValue = (byte[]) value;166if (extValue[0] == DerValue.tag_OctetString) {167this.extensionValue = new DerValue(extValue).getOctetString();168} else {169this.extensionValue = extValue;170}171DerValue val = new DerValue(this.extensionValue);172this.bitString = val.getUnalignedBitString().toBooleanArray();173}174175/**176* Create a default key usage.177*/178public KeyUsageExtension() {179extensionId = PKIXExtensions.KeyUsage_Id;180critical = true;181bitString = new boolean[0];182}183184/**185* Set the attribute value.186*/187public void set(String name, Object obj) throws IOException {188if (!(obj instanceof Boolean)) {189throw new IOException("Attribute must be of type Boolean.");190}191boolean val = ((Boolean)obj).booleanValue();192if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {193set(0,val);194} else if (name.equalsIgnoreCase(NON_REPUDIATION)) {195set(1,val);196} else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {197set(2,val);198} else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {199set(3,val);200} else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {201set(4,val);202} else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {203set(5,val);204} else if (name.equalsIgnoreCase(CRL_SIGN)) {205set(6,val);206} else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {207set(7,val);208} else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {209set(8,val);210} else {211throw new IOException("Attribute name not recognized by"212+ " CertAttrSet:KeyUsage.");213}214encodeThis();215}216217/**218* Get the attribute value.219*/220public Boolean get(String name) throws IOException {221if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {222return Boolean.valueOf(isSet(0));223} else if (name.equalsIgnoreCase(NON_REPUDIATION)) {224return Boolean.valueOf(isSet(1));225} else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {226return Boolean.valueOf(isSet(2));227} else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {228return Boolean.valueOf(isSet(3));229} else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {230return Boolean.valueOf(isSet(4));231} else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {232return Boolean.valueOf(isSet(5));233} else if (name.equalsIgnoreCase(CRL_SIGN)) {234return Boolean.valueOf(isSet(6));235} else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {236return Boolean.valueOf(isSet(7));237} else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {238return Boolean.valueOf(isSet(8));239} else {240throw new IOException("Attribute name not recognized by"241+ " CertAttrSet:KeyUsage.");242}243}244245/**246* Delete the attribute value.247*/248public void delete(String name) throws IOException {249if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {250set(0,false);251} else if (name.equalsIgnoreCase(NON_REPUDIATION)) {252set(1,false);253} else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {254set(2,false);255} else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {256set(3,false);257} else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {258set(4,false);259} else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {260set(5,false);261} else if (name.equalsIgnoreCase(CRL_SIGN)) {262set(6,false);263} else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {264set(7,false);265} else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {266set(8,false);267} else {268throw new IOException("Attribute name not recognized by"269+ " CertAttrSet:KeyUsage.");270}271encodeThis();272}273274/**275* Returns a printable representation of the KeyUsage.276*/277public String toString() {278StringBuilder sb = new StringBuilder();279sb.append(super.toString());280sb.append("KeyUsage [\n");281282if (isSet(0)) {283sb.append(" DigitalSignature\n");284}285if (isSet(1)) {286sb.append(" Non_repudiation\n");287}288if (isSet(2)) {289sb.append(" Key_Encipherment\n");290}291if (isSet(3)) {292sb.append(" Data_Encipherment\n");293}294if (isSet(4)) {295sb.append(" Key_Agreement\n");296}297if (isSet(5)) {298sb.append(" Key_CertSign\n");299}300if (isSet(6)) {301sb.append(" Crl_Sign\n");302}303if (isSet(7)) {304sb.append(" Encipher_Only\n");305}306if (isSet(8)) {307sb.append(" Decipher_Only\n");308}309sb.append("]\n");310311return sb.toString();312}313314/**315* Write the extension to the DerOutputStream.316*317* @param out the DerOutputStream to write the extension to.318* @exception IOException on encoding errors.319*/320public void encode(OutputStream out) throws IOException {321DerOutputStream tmp = new DerOutputStream();322323if (this.extensionValue == null) {324this.extensionId = PKIXExtensions.KeyUsage_Id;325this.critical = true;326encodeThis();327}328super.encode(tmp);329out.write(tmp.toByteArray());330}331332/**333* Return an enumeration of names of attributes existing within this334* attribute.335*/336public Enumeration<String> getElements() {337AttributeNameEnumeration elements = new AttributeNameEnumeration();338elements.addElement(DIGITAL_SIGNATURE);339elements.addElement(NON_REPUDIATION);340elements.addElement(KEY_ENCIPHERMENT);341elements.addElement(DATA_ENCIPHERMENT);342elements.addElement(KEY_AGREEMENT);343elements.addElement(KEY_CERTSIGN);344elements.addElement(CRL_SIGN);345elements.addElement(ENCIPHER_ONLY);346elements.addElement(DECIPHER_ONLY);347348return (elements.elements());349}350351352public boolean[] getBits() {353return bitString.clone();354}355356/**357* Return the name of this attribute.358*/359public String getName() {360return (NAME);361}362}363364365