1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.harmony.xnet.provider.jsse; 18 19 import java.security.DigestException; 20 import java.security.InvalidKeyException; 21 import java.security.MessageDigest; 22 import java.security.NoSuchAlgorithmException; 23 import java.security.PrivateKey; 24 import java.security.Signature; 25 import java.security.SignatureException; 26 import java.security.cert.Certificate; 27 import java.util.Arrays; 28 import javax.crypto.BadPaddingException; 29 import javax.crypto.Cipher; 30 import javax.crypto.IllegalBlockSizeException; 31 import javax.crypto.NoSuchPaddingException; 32 import javax.net.ssl.SSLException; 33 34 /** 35 * This class represents Signature type, as described in TLS v 1.0 Protocol 36 * specification, 7.4.3. It allow to init, update and sign hash. Hash algorithm 37 * depends on SignatureAlgorithm. 38 * 39 * select (SignatureAlgorithm) 40 * { case anonymous: struct { }; 41 * case rsa: 42 * digitally-signed struct { 43 * opaque md5_hash[16]; 44 * opaque sha_hash[20]; 45 * }; 46 * case dsa: 47 * digitally-signed struct { 48 * opaque sha_hash[20]; 49 * }; 50 * } Signature; 51 * 52 * Digital signing description see in TLS spec., 4.7. 53 * (http://www.ietf.org/rfc/rfc2246.txt) 54 * 55 */ 56 public class DigitalSignature { 57 58 private final MessageDigest md5; 59 private final MessageDigest sha; 60 private final Signature signature; 61 private final Cipher cipher; 62 63 private byte[] md5_hash; 64 private byte[] sha_hash; 65 66 /** 67 * Create Signature type 68 * @param keyExchange 69 */ 70 public DigitalSignature(String authType) { 71 try { 72 sha = MessageDigest.getInstance("SHA-1"); 73 74 if ("RSA".equals(authType)) { 75 md5 = MessageDigest.getInstance("MD5"); 76 cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 77 signature = null; 78 } else if ("DSA".equals(authType)) { 79 // SignatureAlgorithm is dsa 80 signature = Signature.getInstance("NONEwithDSA"); 81 cipher = null; 82 md5 = null; 83 } else { 84 cipher = null; 85 signature = null; 86 md5 = null; 87 } 88 } catch (NoSuchAlgorithmException e) { 89 // this should never happen 90 throw new AssertionError(e); 91 } catch (NoSuchPaddingException e) { 92 // this should never happen 93 throw new AssertionError(e); 94 } 95 } 96 97 /** 98 * Initiate Signature type by private key 99 * @param key 100 */ 101 public void init(PrivateKey key) { 102 try { 103 if (signature != null) { 104 signature.initSign(key); 105 } else if (cipher != null) { 106 cipher.init(Cipher.ENCRYPT_MODE, key); 107 } 108 } catch (InvalidKeyException e){ 109 throw new AlertException(AlertProtocol.BAD_CERTIFICATE, 110 new SSLException("init - invalid private key", e)); 111 } 112 } 113 114 /** 115 * Initiate Signature type by certificate 116 * @param cert 117 */ 118 public void init(Certificate cert) { 119 try { 120 if (signature != null) { 121 signature.initVerify(cert); 122 } else if (cipher != null) { 123 cipher.init(Cipher.DECRYPT_MODE, cert); 124 } 125 } catch (InvalidKeyException e){ 126 throw new AlertException(AlertProtocol.BAD_CERTIFICATE, 127 new SSLException("init - invalid certificate", e)); 128 } 129 } 130 131 /** 132 * Update Signature hash 133 * @param data 134 */ 135 public void update(byte[] data) { 136 if (sha != null) { 137 sha.update(data); 138 } 139 if (md5 != null) { 140 md5.update(data); 141 } 142 } 143 144 /** 145 * Sets MD5 hash 146 * @param data 147 */ 148 public void setMD5(byte[] data) { 149 md5_hash = data; 150 } 151 152 /** 153 * Sets SHA hash 154 * @param data 155 */ 156 public void setSHA(byte[] data) { 157 sha_hash = data; 158 } 159 160 /** 161 * Sign hash 162 * @return Signature bytes 163 */ 164 public byte[] sign() { 165 try { 166 if (md5 != null && md5_hash == null) { 167 md5_hash = new byte[16]; 168 md5.digest(md5_hash, 0, md5_hash.length); 169 } 170 if (md5_hash != null) { 171 if (signature != null) { 172 signature.update(md5_hash); 173 } else if (cipher != null) { 174 cipher.update(md5_hash); 175 } 176 } 177 if (sha != null && sha_hash == null) { 178 sha_hash = new byte[20]; 179 sha.digest(sha_hash, 0, sha_hash.length); 180 } 181 if (sha_hash != null) { 182 if (signature != null) { 183 signature.update(sha_hash); 184 } else if (cipher != null) { 185 cipher.update(sha_hash); 186 } 187 } 188 if (signature != null) { 189 return signature.sign(); 190 } else if (cipher != null) { 191 return cipher.doFinal(); 192 } 193 return new byte[0]; 194 } catch (DigestException e){ 195 return new byte[0]; 196 } catch (SignatureException e){ 197 return new byte[0]; 198 } catch (BadPaddingException e){ 199 return new byte[0]; 200 } catch (IllegalBlockSizeException e){ 201 return new byte[0]; 202 } 203 } 204 205 /** 206 * Verifies the signature data. 207 * @param data - the signature bytes 208 * @return true if verified 209 */ 210 public boolean verifySignature(byte[] data) { 211 if (signature != null) { 212 try { 213 signature.update(sha_hash); 214 return signature.verify(data); 215 } catch (SignatureException e) { 216 return false; 217 } 218 } 219 220 if (cipher != null) { 221 final byte[] decrypt; 222 try { 223 decrypt = cipher.doFinal(data); 224 } catch (IllegalBlockSizeException e) { 225 return false; 226 } catch (BadPaddingException e) { 227 return false; 228 } 229 230 final byte[] md5_sha; 231 if (md5_hash != null && sha_hash != null) { 232 md5_sha = new byte[md5_hash.length + sha_hash.length]; 233 System.arraycopy(md5_hash, 0, md5_sha, 0, md5_hash.length); 234 System.arraycopy(sha_hash, 0, md5_sha, md5_hash.length, sha_hash.length); 235 } else if (md5_hash != null) { 236 md5_sha = md5_hash; 237 } else { 238 md5_sha = sha_hash; 239 } 240 241 return Arrays.equals(decrypt, md5_sha); 242 } else if (data == null || data.length == 0) { 243 return true; 244 } else { 245 return false; 246 } 247 } 248 249 } 250