1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/**
6 * Licensed to the Apache Software Foundation (ASF) under one
7 * or more contributor license agreements. See the NOTICE file
8 * distributed with this work for additional information
9 * regarding copyright ownership. The ASF licenses this file
10 * to you under the Apache License, Version 2.0 (the
11 * "License"); you may not use this file except in compliance
12 * with the License. You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing,
17 * software distributed under the License is distributed on an
18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 * KIND, either express or implied. See the License for the
20 * specific language governing permissions and limitations
21 * under the License.
22 */
23package com.sun.org.apache.xml.internal.security.keys.content.x509;
24
25import java.security.cert.X509Certificate;
26import java.util.Arrays;
27
28import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
29import com.sun.org.apache.xml.internal.security.utils.Base64;
30import com.sun.org.apache.xml.internal.security.utils.Constants;
31import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
32import org.w3c.dom.Document;
33import org.w3c.dom.Element;
34
35/**
36 * Handles SubjectKeyIdentifier (SKI) for X.509v3.
37 *
38 * @see <A HREF="http://docs.oracle.com/javase/1.5.0/docs/api/java/security/cert/X509Extension.html">
39 * Interface X509Extension</A>
40 */
41public class XMLX509SKI extends SignatureElementProxy implements XMLX509DataContent {
42
43    /** {@link org.apache.commons.logging} logging facility */
44    private static java.util.logging.Logger log =
45        java.util.logging.Logger.getLogger(XMLX509SKI.class.getName());
46
47    /**
48     * <CODE>SubjectKeyIdentifier (id-ce-subjectKeyIdentifier) (2.5.29.14)</CODE>:
49     * This extension identifies the public key being certified. It enables
50     * distinct keys used by the same subject to be differentiated
51     * (e.g., as key updating occurs).
52     * <BR />
53     * A key identifier shall be unique with respect to all key identifiers
54     * for the subject with which it is used. This extension is always non-critical.
55     */
56    public static final String SKI_OID = "2.5.29.14";
57
58    /**
59     * Constructor X509SKI
60     *
61     * @param doc
62     * @param skiBytes
63     */
64    public XMLX509SKI(Document doc, byte[] skiBytes) {
65        super(doc);
66        this.addBase64Text(skiBytes);
67    }
68
69    /**
70     * Constructor XMLX509SKI
71     *
72     * @param doc
73     * @param x509certificate
74     * @throws XMLSecurityException
75     */
76    public XMLX509SKI(Document doc, X509Certificate x509certificate)
77        throws XMLSecurityException {
78        super(doc);
79        this.addBase64Text(XMLX509SKI.getSKIBytesFromCert(x509certificate));
80    }
81
82    /**
83     * Constructor XMLX509SKI
84     *
85     * @param element
86     * @param BaseURI
87     * @throws XMLSecurityException
88     */
89    public XMLX509SKI(Element element, String BaseURI) throws XMLSecurityException {
90        super(element, BaseURI);
91    }
92
93    /**
94     * Method getSKIBytes
95     *
96     * @return the skibytes
97     * @throws XMLSecurityException
98     */
99    public byte[] getSKIBytes() throws XMLSecurityException {
100        return this.getBytesFromTextChild();
101    }
102
103    /**
104     * Method getSKIBytesFromCert
105     *
106     * @param cert
107     * @return ski bytes from the given certificate
108     *
109     * @throws XMLSecurityException
110     * @see java.security.cert.X509Extension#getExtensionValue(java.lang.String)
111     */
112    public static byte[] getSKIBytesFromCert(X509Certificate cert)
113        throws XMLSecurityException {
114
115        if (cert.getVersion() < 3) {
116            Object exArgs[] = { Integer.valueOf(cert.getVersion()) };
117            throw new XMLSecurityException("certificate.noSki.lowVersion", exArgs);
118        }
119
120        /*
121         * Gets the DER-encoded OCTET string for the extension value
122         * (extnValue) identified by the passed-in oid String. The oid
123         * string is represented by a set of positive whole numbers
124         * separated by periods.
125         */
126        byte[] extensionValue = cert.getExtensionValue(XMLX509SKI.SKI_OID);
127        if (extensionValue == null) {
128            throw new XMLSecurityException("certificate.noSki.null");
129        }
130
131        /**
132         * Strip away first four bytes from the extensionValue
133         * The first two bytes are the tag and length of the extensionValue
134         * OCTET STRING, and the next two bytes are the tag and length of
135         * the ski OCTET STRING.
136         */
137        byte skidValue[] = new byte[extensionValue.length - 4];
138
139        System.arraycopy(extensionValue, 4, skidValue, 0, skidValue.length);
140
141        if (log.isLoggable(java.util.logging.Level.FINE)) {
142            log.log(java.util.logging.Level.FINE, "Base64 of SKI is " + Base64.encode(skidValue));
143        }
144
145        return skidValue;
146    }
147
148    /** @inheritDoc */
149    public boolean equals(Object obj) {
150        if (!(obj instanceof XMLX509SKI)) {
151            return false;
152        }
153
154        XMLX509SKI other = (XMLX509SKI) obj;
155
156        try {
157            return Arrays.equals(other.getSKIBytes(), this.getSKIBytes());
158        } catch (XMLSecurityException ex) {
159            return false;
160        }
161    }
162
163    public int hashCode() {
164        int result = 17;
165        try {
166            byte[] bytes = getSKIBytes();
167            for (int i = 0; i < bytes.length; i++) {
168                result = 31 * result + bytes[i];
169            }
170        } catch (XMLSecurityException e) {
171            if (log.isLoggable(java.util.logging.Level.FINE)) {
172                log.log(java.util.logging.Level.FINE, e.getMessage(), e);
173            }
174        }
175        return result;
176
177    }
178
179    /** @inheritDoc */
180    public String getBaseLocalName() {
181        return Constants._TAG_X509SKI;
182    }
183}
184