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 17 package org.apache.harmony.xnet.provider.jsse; 18 19 import java.security.InvalidKeyException; 20 import java.security.InvalidParameterException; 21 import java.security.NoSuchAlgorithmException; 22 import java.security.PrivateKey; 23 import java.security.PublicKey; 24 import java.security.Signature; 25 import java.security.SignatureException; 26 import java.security.interfaces.DSAPrivateKey; 27 import java.security.interfaces.DSAPublicKey; 28 import java.security.interfaces.RSAPrivateCrtKey; 29 import java.security.interfaces.RSAPrivateKey; 30 import java.security.interfaces.RSAPublicKey; 31 32 /** 33 * Implements the subset of the JDK Signature interface needed for 34 * signature verification using OpenSSL. 35 */ 36 public class OpenSSLSignature extends Signature { 37 private static enum EngineType { 38 RSA, DSA, 39 }; 40 41 /** 42 * Holds a pointer to the native message digest context. 43 */ 44 private int ctx; 45 46 /** 47 * The current OpenSSL key we're operating on. 48 */ 49 private OpenSSLKey key; 50 51 /** 52 * Holds the type of the Java algorithm. 53 */ 54 private final EngineType engineType; 55 56 /** 57 * Holds the OpenSSL name of the algorithm (lower case, no dashes). 58 */ 59 private final String evpAlgorithm; 60 61 /** 62 * Holds a dummy buffer for writing single bytes to the digest. 63 */ 64 private final byte[] singleByte = new byte[1]; 65 66 /** 67 * Creates a new OpenSSLSignature instance for the given algorithm name. 68 * 69 * @param algorithm OpenSSL name of the algorithm, e.g. "RSA-SHA1". 70 */ 71 private OpenSSLSignature(String algorithm, EngineType engineType) 72 throws NoSuchAlgorithmException { 73 super(algorithm); 74 75 // We don't support MD2 76 if ("RSA-MD2".equals(algorithm)) { 77 throw new NoSuchAlgorithmException(algorithm); 78 } 79 80 this.engineType = engineType; 81 this.evpAlgorithm = algorithm; 82 } 83 84 @Override 85 protected void engineUpdate(byte input) { 86 singleByte[0] = input; 87 engineUpdate(singleByte, 0, 1); 88 } 89 90 @Override 91 protected void engineUpdate(byte[] input, int offset, int len) { 92 if (state == SIGN) { 93 if (ctx == 0) { 94 try { 95 ctx = NativeCrypto.EVP_SignInit(evpAlgorithm); 96 } catch (Exception ex) { 97 throw new RuntimeException(ex); 98 } 99 } 100 101 NativeCrypto.EVP_SignUpdate(ctx, input, offset, len); 102 } else { 103 if (ctx == 0) { 104 try { 105 ctx = NativeCrypto.EVP_VerifyInit(evpAlgorithm); 106 } catch (Exception ex) { 107 throw new RuntimeException(ex); 108 } 109 } 110 111 NativeCrypto.EVP_VerifyUpdate(ctx, input, offset, len); 112 } 113 } 114 115 @Override 116 protected Object engineGetParameter(String param) throws InvalidParameterException { 117 return null; 118 } 119 120 @Override 121 protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { 122 destroyContextIfExists(); 123 124 if (privateKey instanceof OpenSSLDSAPrivateKey) { 125 if (engineType != EngineType.DSA) { 126 throw new InvalidKeyException("Signature not initialized as DSA"); 127 } 128 129 OpenSSLDSAPrivateKey dsaPrivateKey = (OpenSSLDSAPrivateKey) privateKey; 130 key = dsaPrivateKey.getOpenSSLKey(); 131 } else if (privateKey instanceof DSAPrivateKey) { 132 if (engineType != EngineType.DSA) { 133 throw new InvalidKeyException("Signature not initialized as DSA"); 134 } 135 136 DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privateKey; 137 key = OpenSSLDSAPrivateKey.getInstance(dsaPrivateKey); 138 } else if (privateKey instanceof OpenSSLRSAPrivateKey) { 139 if (engineType != EngineType.RSA) { 140 throw new InvalidKeyException("Signature not initialized as RSA"); 141 } 142 143 OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) privateKey; 144 key = rsaPrivateKey.getOpenSSLKey(); 145 } else if (privateKey instanceof RSAPrivateCrtKey) { 146 if (engineType != EngineType.RSA) { 147 throw new InvalidKeyException("Signature not initialized as RSA"); 148 } 149 150 RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey; 151 key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey); 152 } else if (privateKey instanceof RSAPrivateKey) { 153 if (engineType != EngineType.RSA) { 154 throw new InvalidKeyException("Signature not initialized as RSA"); 155 } 156 157 RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey; 158 key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey); 159 } else { 160 throw new InvalidKeyException("Need DSA or RSA private key"); 161 } 162 } 163 164 @Override 165 protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { 166 // If we had an existing context, destroy it first. 167 destroyContextIfExists(); 168 169 if (publicKey instanceof OpenSSLDSAPublicKey) { 170 if (engineType != EngineType.DSA) { 171 throw new InvalidKeyException("Signature not initialized as DSA"); 172 } 173 174 OpenSSLDSAPublicKey dsaPublicKey = (OpenSSLDSAPublicKey) publicKey; 175 key = dsaPublicKey.getOpenSSLKey(); 176 } else if (publicKey instanceof DSAPublicKey) { 177 if (engineType != EngineType.DSA) { 178 throw new InvalidKeyException("Signature not initialized as DSA"); 179 } 180 181 DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey; 182 key = OpenSSLDSAPublicKey.getInstance(dsaPublicKey); 183 } else if (publicKey instanceof OpenSSLRSAPublicKey) { 184 if (engineType != EngineType.RSA) { 185 throw new InvalidKeyException("Signature not initialized as RSA"); 186 } 187 188 OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) publicKey; 189 key = rsaPublicKey.getOpenSSLKey(); 190 } else if (publicKey instanceof RSAPublicKey) { 191 if (engineType != EngineType.RSA) { 192 throw new InvalidKeyException("Signature not initialized as RSA"); 193 } 194 195 RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; 196 key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey); 197 } else { 198 throw new InvalidKeyException("Need DSA or RSA public key"); 199 } 200 } 201 202 @Override 203 protected void engineSetParameter(String param, Object value) throws InvalidParameterException { 204 } 205 206 @Override 207 protected byte[] engineSign() throws SignatureException { 208 if (key == null) { 209 // This can't actually happen, but you never know... 210 throw new SignatureException("Need DSA or RSA private key"); 211 } 212 213 try { 214 byte[] buffer = new byte[NativeCrypto.EVP_PKEY_size(key.getPkeyContext())]; 215 int bytesWritten = NativeCrypto.EVP_SignFinal(ctx, buffer, 0, key.getPkeyContext()); 216 217 byte[] signature = new byte[bytesWritten]; 218 System.arraycopy(buffer, 0, signature, 0, bytesWritten); 219 220 return signature; 221 } catch (Exception ex) { 222 throw new SignatureException(ex); 223 } finally { 224 /* 225 * Java expects the digest context to be reset completely after sign 226 * calls. 227 */ 228 destroyContextIfExists(); 229 } 230 } 231 232 @Override 233 protected boolean engineVerify(byte[] sigBytes) throws SignatureException { 234 if (key == null) { 235 // This can't actually happen, but you never know... 236 throw new SignatureException("Need DSA or RSA public key"); 237 } 238 239 try { 240 int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length, 241 key.getPkeyContext()); 242 return result == 1; 243 } catch (Exception ex) { 244 throw new SignatureException(ex); 245 } finally { 246 /* 247 * Java expects the digest context to be reset completely after 248 * verify calls. 249 */ 250 destroyContextIfExists(); 251 } 252 } 253 254 private void destroyContextIfExists() { 255 if (ctx != 0) { 256 NativeCrypto.EVP_MD_CTX_destroy(ctx); 257 ctx = 0; 258 } 259 } 260 261 @Override 262 protected void finalize() throws Throwable { 263 try { 264 if (ctx != 0) { 265 NativeCrypto.EVP_MD_CTX_destroy(ctx); 266 } 267 } finally { 268 super.finalize(); 269 } 270 } 271 272 public static final class MD5RSA extends OpenSSLSignature { 273 public MD5RSA() throws NoSuchAlgorithmException { 274 super("RSA-MD5", EngineType.RSA); 275 } 276 } 277 public static final class SHA1RSA extends OpenSSLSignature { 278 public SHA1RSA() throws NoSuchAlgorithmException { 279 super("RSA-SHA1", EngineType.RSA); 280 } 281 } 282 public static final class SHA256RSA extends OpenSSLSignature { 283 public SHA256RSA() throws NoSuchAlgorithmException { 284 super("RSA-SHA256", EngineType.RSA); 285 } 286 } 287 public static final class SHA384RSA extends OpenSSLSignature { 288 public SHA384RSA() throws NoSuchAlgorithmException { 289 super("RSA-SHA384", EngineType.RSA); 290 } 291 } 292 public static final class SHA512RSA extends OpenSSLSignature { 293 public SHA512RSA() throws NoSuchAlgorithmException { 294 super("RSA-SHA512", EngineType.RSA); 295 } 296 } 297 public static final class SHA1DSA extends OpenSSLSignature { 298 public SHA1DSA() throws NoSuchAlgorithmException { 299 super("DSA-SHA1", EngineType.DSA); 300 } 301 } 302 } 303 304