1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.conscrypt.ct;
18
19import java.io.ByteArrayInputStream;
20import java.io.InputStream;
21import org.conscrypt.Internal;
22
23/**
24 * DigitallySigned structure, as defined by RFC5246 Section 4.7.
25 *
26 * @hide
27 */
28@Internal
29public class DigitallySigned {
30    public enum HashAlgorithm {
31        NONE,
32        MD5,
33        SHA1,
34        SHA224,
35        SHA256,
36        SHA384,
37        SHA512;
38
39        private static HashAlgorithm[] values = values();
40        public static HashAlgorithm valueOf(int ord) {
41            try {
42                return values[ord];
43            } catch (IndexOutOfBoundsException e) {
44                throw new IllegalArgumentException("Invalid hash algorithm " + ord, e);
45            }
46        }
47    }
48
49    public enum SignatureAlgorithm {
50        ANONYMOUS,
51        RSA,
52        DSA,
53        ECDSA;
54
55        private static SignatureAlgorithm[] values = values();
56        public static SignatureAlgorithm valueOf(int ord) {
57            try {
58                return values[ord];
59            } catch (IndexOutOfBoundsException e) {
60                throw new IllegalArgumentException("Invalid signature algorithm " + ord, e);
61            }
62        }
63    }
64
65    private final HashAlgorithm hashAlgorithm;
66    private final SignatureAlgorithm signatureAlgorithm;
67    private final byte[] signature;
68
69    public DigitallySigned(HashAlgorithm hashAlgorithm,
70                           SignatureAlgorithm signatureAlgorithm,
71                           byte[] signature) {
72        this.hashAlgorithm = hashAlgorithm;
73        this.signatureAlgorithm = signatureAlgorithm;
74        this.signature = signature;
75    }
76
77    public DigitallySigned(int hashAlgorithm,
78                           int signatureAlgorithm,
79                           byte[] signature) {
80        this(
81            HashAlgorithm.valueOf(hashAlgorithm),
82            SignatureAlgorithm.valueOf(signatureAlgorithm),
83            signature
84        );
85    }
86
87    public HashAlgorithm getHashAlgorithm() {
88        return hashAlgorithm;
89    }
90    public SignatureAlgorithm getSignatureAlgorithm() {
91        return signatureAlgorithm;
92    }
93    public byte[] getSignature() {
94        return signature;
95    }
96
97    /**
98     * Get the name of the hash and signature combination.
99     * The result can be used to as the argument to {@link java.security.Signature#getInstance}.
100     */
101    public String getAlgorithm() {
102        return String.format("%swith%s", hashAlgorithm, signatureAlgorithm);
103    }
104
105    /**
106     * Decode a TLS encoded DigitallySigned structure.
107     */
108    public static DigitallySigned decode(InputStream input)
109        throws SerializationException {
110        try {
111            return new DigitallySigned(
112                Serialization.readNumber(input, CTConstants.HASH_ALGORITHM_LENGTH),
113                Serialization.readNumber(input, CTConstants.SIGNATURE_ALGORITHM_LENGTH),
114                Serialization.readVariableBytes(input, CTConstants.SIGNATURE_LENGTH_BYTES)
115            );
116        } catch (IllegalArgumentException e) {
117            throw new SerializationException(e);
118        }
119    }
120
121    /**
122     * Decode a TLS encoded DigitallySigned structure.
123     */
124    public static DigitallySigned decode(byte[] input)
125            throws SerializationException {
126        return decode(new ByteArrayInputStream(input));
127    }
128}
129
130
131