OpenSSLSignature.java revision a3de55ddf81f95c7c0fc1b8767ccb1ecfa251c83
1/* 2 * Copyright (C) 2008 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.apache.harmony.xnet.provider.jsse; 18 19import java.security.InvalidKeyException; 20import java.security.InvalidParameterException; 21import java.security.NoSuchAlgorithmException; 22import java.security.PrivateKey; 23import java.security.PublicKey; 24import java.security.Signature; 25import java.security.SignatureException; 26import java.security.interfaces.DSAParams; 27import java.security.interfaces.DSAPublicKey; 28import java.security.interfaces.RSAPublicKey; 29import java.util.HashMap; 30import java.util.Map; 31 32/** 33 * Implements the subset of the JDK Signature interface needed for 34 * signature verification using OpenSSL. 35 */ 36public class OpenSSLSignature extends Signature { 37 38 private static Map<String,Class<? extends OpenSSLSignature>> jdkToOpenSsl 39 = new HashMap<String,Class<? extends OpenSSLSignature>>(); 40 41 static { 42 // TODO Finish OpenSSLSignature implementation and move 43 // registration information to the OpenSSLProvider 44 jdkToOpenSsl.put("MD5WithRSAEncryption", MD5RSA.class); 45 jdkToOpenSsl.put("MD5WithRSA", MD5RSA.class); 46 jdkToOpenSsl.put("MD5/RSA", MD5RSA.class); 47 jdkToOpenSsl.put("1.2.840.113549.1.1.4", MD5RSA.class); 48 jdkToOpenSsl.put("1.2.840.113549.2.5with1.2.840.113549.1.1.1", MD5RSA.class); 49 50 jdkToOpenSsl.put("SHA1WithRSAEncryption", SHA1RSA.class); 51 jdkToOpenSsl.put("SHA1WithRSA", SHA1RSA.class); 52 jdkToOpenSsl.put("SHA1/RSA", SHA1RSA.class); 53 jdkToOpenSsl.put("SHA-1/RSA", SHA1RSA.class); 54 jdkToOpenSsl.put("1.2.840.113549.1.1.5", SHA1RSA.class); 55 jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.113549.1.1.1", SHA1RSA.class); 56 jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.113549.1.1.5", SHA1RSA.class); 57 jdkToOpenSsl.put("1.3.14.3.2.29", SHA1RSA.class); 58 59 jdkToOpenSsl.put("SHA256WithRSAEncryption", SHA256RSA.class); 60 jdkToOpenSsl.put("SHA256WithRSA", SHA256RSA.class); 61 jdkToOpenSsl.put("1.2.840.113549.1.1.11", SHA256RSA.class); 62 63 jdkToOpenSsl.put("SHA384WithRSAEncryption", SHA384RSA.class); 64 jdkToOpenSsl.put("SHA384WithRSA", SHA384RSA.class); 65 jdkToOpenSsl.put("1.2.840.113549.1.1.12", SHA384RSA.class); 66 67 jdkToOpenSsl.put("SHA512WithRSAEncryption", SHA512RSA.class); 68 jdkToOpenSsl.put("SHA512WithRSA", SHA512RSA.class); 69 jdkToOpenSsl.put("1.2.840.113549.1.1.13", SHA512RSA.class); 70 71 jdkToOpenSsl.put("SHA1withDSA", SHA1DSA.class); 72 jdkToOpenSsl.put("SHA/DSA", SHA1DSA.class); 73 jdkToOpenSsl.put("DSA", SHA1DSA.class); 74 jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.10040.4.1", SHA1DSA.class); 75 jdkToOpenSsl.put("1.3.14.3.2.26with1.2.840.10040.4.3", SHA1DSA.class); 76 jdkToOpenSsl.put("DSAWithSHA1", SHA1DSA.class); 77 jdkToOpenSsl.put("1.2.840.10040.4.3", SHA1DSA.class); 78 } 79 80 /** 81 * Holds a pointer to the native message digest context. 82 */ 83 private final int ctx; 84 85 /** 86 * Holds a pointer to the native DSA key. 87 */ 88 private int dsa; 89 90 /** 91 * Holds a pointer to the native RSA key. 92 */ 93 private int rsa; 94 95 /** 96 * Holds the OpenSSL name of the algorithm (lower case, no dashes). 97 */ 98 private final String evpAlgorithm; 99 100 /** 101 * Holds a dummy buffer for writing single bytes to the digest. 102 */ 103 private final byte[] singleByte = new byte[1]; 104 105 /** 106 * Creates a new OpenSSLSignature instance for the given algorithm name. 107 * 108 * @param algorithm The name of the algorithm, e.g. "SHA1WithRSA". 109 * 110 * @return The new OpenSSLSignature instance. 111 * 112 * @throws RuntimeException In case of problems. 113 */ 114 public static OpenSSLSignature getInstance(String algorithm) throws NoSuchAlgorithmException { 115 // System.out.println("getInstance() invoked with " + algorithm); 116 117 Class <? extends OpenSSLSignature> clazz = jdkToOpenSsl.get(algorithm); 118 if (clazz == null) { 119 throw new NoSuchAlgorithmException(algorithm); 120 } 121 try { 122 return clazz.newInstance(); 123 } catch (InstantiationException e) { 124 throw new NoSuchAlgorithmException(algorithm, e); 125 } catch (IllegalAccessException e) { 126 throw new NoSuchAlgorithmException(algorithm, e); 127 } 128 } 129 130 /** 131 * Creates a new OpenSSLSignature instance for the given algorithm name. 132 * 133 * @param algorithm OpenSSL name of the algorithm, e.g. "RSA-SHA1". 134 */ 135 private OpenSSLSignature(String algorithm) throws NoSuchAlgorithmException { 136 super(algorithm); 137 138 // We don't support MD2 139 if ("RSA-MD2".equals(algorithm)) { 140 throw new NoSuchAlgorithmException(algorithm); 141 } 142 143 this.evpAlgorithm = algorithm; 144 this.ctx = NativeCrypto.EVP_MD_CTX_create(); 145 } 146 147 @Override 148 protected void engineUpdate(byte input) { 149 singleByte[0] = input; 150 engineUpdate(singleByte, 0, 1); 151 } 152 153 @Override 154 protected void engineUpdate(byte[] input, int offset, int len) { 155 if (state == SIGN) { 156 throw new UnsupportedOperationException(); 157 } else { 158 NativeCrypto.EVP_VerifyUpdate(ctx, input, offset, len); 159 } 160 } 161 162 @Override 163 protected Object engineGetParameter(String param) throws InvalidParameterException { 164 return null; 165 } 166 167 @Override 168 protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { 169 throw new UnsupportedOperationException(); 170 } 171 172 @Override 173 protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { 174 // System.out.println("engineInitVerify() invoked with " 175 // + publicKey.getClass().getCanonicalName()); 176 177 if (publicKey instanceof DSAPublicKey) { 178 try { 179 DSAPublicKey dsaPublicKey = (DSAPublicKey)publicKey; 180 DSAParams dsaParams = dsaPublicKey.getParams(); 181 dsa = NativeCrypto.EVP_PKEY_new_DSA(dsaParams.getP().toByteArray(), 182 dsaParams.getQ().toByteArray(), dsaParams.getG().toByteArray(), 183 dsaPublicKey.getY().toByteArray(), null); 184 185 } catch (Exception ex) { 186 throw new InvalidKeyException(ex.toString()); 187 } 188 } else if (publicKey instanceof RSAPublicKey) { 189 try { 190 RSAPublicKey rsaPublicKey = (RSAPublicKey)publicKey; 191 rsa = NativeCrypto.EVP_PKEY_new_RSA(rsaPublicKey.getModulus().toByteArray(), 192 rsaPublicKey.getPublicExponent().toByteArray(), null, null, null); 193 194 } catch (Exception ex) { 195 throw new InvalidKeyException(ex.toString()); 196 } 197 } else { 198 throw new InvalidKeyException("Need DSA or RSA public key"); 199 } 200 201 try { 202 NativeCrypto.EVP_VerifyInit(ctx, evpAlgorithm); 203 } catch (Exception ex) { 204 throw new RuntimeException(ex); 205 } 206 } 207 208 @Override 209 protected void engineSetParameter(String param, Object value) throws InvalidParameterException { 210 } 211 212 @Override 213 protected byte[] engineSign() throws SignatureException { 214 throw new UnsupportedOperationException(); 215 } 216 217 @Override 218 protected boolean engineVerify(byte[] sigBytes) throws SignatureException { 219 int handle = (rsa != 0) ? rsa : dsa; 220 221 if (handle == 0) { 222 // This can't actually happen, but you never know... 223 throw new SignatureException("Need DSA or RSA public key"); 224 } 225 226 try { 227 int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length, handle); 228 return result == 1; 229 } catch (Exception ex) { 230 throw new SignatureException(ex); 231 } 232 233 } 234 235 @Override 236 protected void finalize() throws Throwable { 237 super.finalize(); 238 239 if (dsa != 0) { 240 NativeCrypto.EVP_PKEY_free(dsa); 241 } 242 243 if (rsa != 0) { 244 NativeCrypto.EVP_PKEY_free(rsa); 245 } 246 247 if (ctx != 0) { 248 NativeCrypto.EVP_MD_CTX_destroy(ctx); 249 } 250 } 251 252 public static final class MD5RSA extends OpenSSLSignature { 253 public MD5RSA() throws NoSuchAlgorithmException { 254 super("RSA-MD5"); 255 } 256 } 257 public static final class SHA1RSA extends OpenSSLSignature { 258 public SHA1RSA() throws NoSuchAlgorithmException { 259 super("RSA-SHA1"); 260 } 261 } 262 public static final class SHA256RSA extends OpenSSLSignature { 263 public SHA256RSA() throws NoSuchAlgorithmException { 264 super("RSA-SHA256"); 265 } 266 } 267 public static final class SHA384RSA extends OpenSSLSignature { 268 public SHA384RSA() throws NoSuchAlgorithmException { 269 super("RSA-SHA384"); 270 } 271 } 272 public static final class SHA512RSA extends OpenSSLSignature { 273 public SHA512RSA() throws NoSuchAlgorithmException { 274 super("RSA-SHA512"); 275 } 276 } 277 public static final class SHA1DSA extends OpenSSLSignature { 278 public SHA1DSA() throws NoSuchAlgorithmException { 279 super("DSA-SHA1"); 280 } 281 } 282} 283 284