Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java
41159 views
/*1* Copyright (c) 2000, 2019, 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*/2425/*26* (C) Copyright IBM Corp. 1999 All Rights Reserved.27* Copyright 1997 The Open Group Research Institute. All rights reserved.28*/2930package sun.security.krb5;3132import java.util.Arrays;33import sun.security.util.*;34import sun.security.krb5.internal.*;35import sun.security.krb5.internal.crypto.*;36import java.io.IOException;37import java.math.BigInteger;3839/**40* This class encapsulates the concept of a Kerberos checksum.41*/42public class Checksum {4344private int cksumType;45private byte[] checksum;4647// ----------------------------------------------+-------------+-----------48// Checksum type |sumtype |checksum49// |value | size50// ----------------------------------------------+-------------+-----------51public static final int CKSUMTYPE_NULL = 0; // 052public static final int CKSUMTYPE_CRC32 = 1; // 453public static final int CKSUMTYPE_RSA_MD4 = 2; // 1654public static final int CKSUMTYPE_RSA_MD4_DES = 3; // 2455public static final int CKSUMTYPE_DES_MAC = 4; // 1656public static final int CKSUMTYPE_DES_MAC_K = 5; // 857public static final int CKSUMTYPE_RSA_MD4_DES_K = 6; // 1658public static final int CKSUMTYPE_RSA_MD5 = 7; // 1659public static final int CKSUMTYPE_RSA_MD5_DES = 8; // 246061// draft-ietf-krb-wg-crypto-07.txt62public static final int CKSUMTYPE_HMAC_SHA1_DES3_KD = 12; // 206364// draft-raeburn-krb-rijndael-krb-07.txt65public static final int CKSUMTYPE_HMAC_SHA1_96_AES128 = 15; // 9666public static final int CKSUMTYPE_HMAC_SHA1_96_AES256 = 16; // 966768// rfc800969public static final int CKSUMTYPE_HMAC_SHA256_128_AES128 = 19; // 9670public static final int CKSUMTYPE_HMAC_SHA384_192_AES256 = 20; // 967172// draft-brezak-win2k-krb-rc4-hmac-04.txt73public static final int CKSUMTYPE_HMAC_MD5_ARCFOUR = -138;7475// default checksum type, -1 if not set76static int CKSUMTYPE_DEFAULT;77static int SAFECKSUMTYPE_DEFAULT;7879private static boolean DEBUG = Krb5.DEBUG;80static {81initStatic();82}8384public static void initStatic() {85String temp = null;86Config cfg = null;87try {88cfg = Config.getInstance();89temp = cfg.get("libdefaults", "default_checksum");90if (temp != null) {91CKSUMTYPE_DEFAULT = Config.getType(temp);92} else {93CKSUMTYPE_DEFAULT = -1;94}95} catch (Exception exc) {96if (DEBUG) {97System.out.println("Exception in getting default checksum "+98"value from the configuration. " +99"No default checksum set.");100exc.printStackTrace();101}102CKSUMTYPE_DEFAULT = -1;103}104105106try {107temp = cfg.get("libdefaults", "safe_checksum_type");108if (temp != null)109{110SAFECKSUMTYPE_DEFAULT = Config.getType(temp);111} else {112SAFECKSUMTYPE_DEFAULT = -1;113}114} catch (Exception exc) {115if (DEBUG) {116System.out.println("Exception in getting safe default " +117"checksum value " +118"from the configuration. " +119"No safe default checksum set.");120exc.printStackTrace();121}122SAFECKSUMTYPE_DEFAULT = -1;123}124}125126/**127* Constructs a new Checksum using the raw data and type.128*129* This constructor is only used by Authenticator Checksum130* {@link sun.security.jgss.krb5.InitialToken.OverloadedChecksum}131* where the checksum type must be 0x8003132* (see https://tools.ietf.org/html/rfc4121#section-4.1.1)133* and checksum field/value is used to convey service flags,134* channel bindings, and optional delegation information.135* This special type does NOT have a {@link CksumType} and has its136* own calculating and verification rules. It does has the same137* ASN.1 encoding though.138*139* @param data the byte array of checksum.140* @param new_cksumType the type of checksum.141*/142public Checksum(byte[] data, int new_cksumType) {143cksumType = new_cksumType;144checksum = data;145}146147/**148* Constructs a new Checksum by calculating over the data using149* the specified checksum type. If the checksum is unkeyed, key150* and usage are ignored.151*152* @param new_cksumType the type of checksum. If set to -1, the153* {@linkplain EType#checksumType() mandatory checksum type}154* for the encryption type of {@code key} will be used155* @param data the data that needs to be performed a checksum calculation on156* @param key the key used by a keyed checksum157* @param usage the usage used by a keyed checksum158*/159public Checksum(int new_cksumType, byte[] data,160EncryptionKey key, int usage)161throws KdcErrException, KrbApErrException, KrbCryptoException {162if (new_cksumType == -1) {163cksumType = EType.getInstance(key.getEType()).checksumType();164} else {165cksumType = new_cksumType;166}167checksum = CksumType.getInstance(cksumType).calculateChecksum(168data, data.length, key.getBytes(), usage);169}170171/**172* Verifies the keyed checksum over the data passed in.173*/174public boolean verifyKeyedChecksum(byte[] data, EncryptionKey key, int usage)175throws KdcErrException, KrbApErrException, KrbCryptoException {176CksumType cksumEngine = CksumType.getInstance(cksumType);177if (!cksumEngine.isKeyed()) {178throw new KrbApErrException(Krb5.KRB_AP_ERR_INAPP_CKSUM);179} else {180return cksumEngine.verifyChecksum(181data, data.length, key.getBytes(), checksum, usage);182}183}184185186/**187* Verifies the checksum over the data passed in. The checksum might188* be a keyed or not.189*190* =============== ATTENTION! Use with care ==================191* According to https://tools.ietf.org/html/rfc3961#section-6.1,192* An unkeyed checksum should only be used "in limited circumstances193* where the lack of a key does not provide a window for an attack,194* preferably as part of an encrypted message".195*/196public boolean verifyAnyChecksum(byte[] data, EncryptionKey key, int usage)197throws KdcErrException, KrbCryptoException {198return CksumType.getInstance(cksumType).verifyChecksum(199data, data.length, key.getBytes(), checksum, usage);200}201202boolean isEqual(Checksum cksum) throws KdcErrException {203if (cksumType != cksum.cksumType) {204return false;205}206return CksumType.isChecksumEqual(checksum, cksum.checksum);207}208209/**210* Constructs an instance of Checksum from an ASN.1 encoded representation.211* @param encoding a single DER-encoded value.212* @exception Asn1Exception if an error occurs while decoding an ASN1213* encoded data.214* @exception IOException if an I/O error occurs while reading encoded data.215*216*/217public Checksum(DerValue encoding) throws Asn1Exception, IOException {218DerValue der;219if (encoding.getTag() != DerValue.tag_Sequence) {220throw new Asn1Exception(Krb5.ASN1_BAD_ID);221}222der = encoding.getData().getDerValue();223if ((der.getTag() & (byte)0x1F) == (byte)0x00) {224cksumType = der.getData().getBigInteger().intValue();225}226else227throw new Asn1Exception(Krb5.ASN1_BAD_ID);228der = encoding.getData().getDerValue();229if ((der.getTag() & (byte)0x1F) == (byte)0x01) {230checksum = der.getData().getOctetString();231}232else233throw new Asn1Exception(Krb5.ASN1_BAD_ID);234if (encoding.getData().available() > 0) {235throw new Asn1Exception(Krb5.ASN1_BAD_ID);236}237}238239/**240* Encodes a Checksum object.241* <pre>{@code242* Checksum ::= SEQUENCE {243* cksumtype [0] Int32,244* checksum [1] OCTET STRING245* }246* }</pre>247*248* <p>249* This definition reflects the Network Working Group RFC 4120250* specification available at251* <a href="http://www.ietf.org/rfc/rfc4120.txt">252* http://www.ietf.org/rfc/rfc4120.txt</a>.253* @return byte array of enocded Checksum.254* @exception Asn1Exception if an error occurs while decoding an255* ASN1 encoded data.256* @exception IOException if an I/O error occurs while reading257* encoded data.258*259*/260public byte[] asn1Encode() throws Asn1Exception, IOException {261DerOutputStream bytes = new DerOutputStream();262DerOutputStream temp = new DerOutputStream();263temp.putInteger(BigInteger.valueOf(cksumType));264bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,265true, (byte)0x00), temp);266temp = new DerOutputStream();267temp.putOctetString(checksum);268bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,269true, (byte)0x01), temp);270temp = new DerOutputStream();271temp.write(DerValue.tag_Sequence, bytes);272return temp.toByteArray();273}274275276/**277* Parse (unmarshal) a checksum object from a DER input stream. This form278* parsing might be used when expanding a value which is part of279* a constructed sequence and uses explicitly tagged type.280*281* @exception Asn1Exception if an error occurs while decoding an282* ASN1 encoded data.283* @exception IOException if an I/O error occurs while reading284* encoded data.285* @param data the Der input stream value, which contains one or more286* marshaled value.287* @param explicitTag tag number.288* @param optional indicates if this data field is optional289* @return an instance of Checksum.290*291*/292public static Checksum parse(DerInputStream data,293byte explicitTag, boolean optional)294throws Asn1Exception, IOException {295296if ((optional) &&297(((byte)data.peekByte() & (byte)0x1F) != explicitTag)) {298return null;299}300DerValue der = data.getDerValue();301if (explicitTag != (der.getTag() & (byte)0x1F)) {302throw new Asn1Exception(Krb5.ASN1_BAD_ID);303} else {304DerValue subDer = der.getData().getDerValue();305return new Checksum(subDer);306}307}308309/**310* Returns the raw bytes of the checksum, not in ASN.1 encoded form.311*/312public final byte[] getBytes() {313return checksum;314}315316public final int getType() {317return cksumType;318}319320@Override public boolean equals(Object obj) {321if (this == obj) {322return true;323}324if (!(obj instanceof Checksum)) {325return false;326}327328try {329return isEqual((Checksum)obj);330} catch (KdcErrException kee) {331return false;332}333}334335@Override public int hashCode() {336int result = 17;337result = 37 * result + cksumType;338if (checksum != null) {339result = 37 * result + Arrays.hashCode(checksum);340}341return result;342}343}344345346