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; 29 30/** 31 * Implements the JDK MessageDigest interface using OpenSSL's EVP API. 32 */ 33public class OpenSSLSignature extends Signature { 34 35 /** 36 * Holds a pointer to the native message digest context. 37 */ 38 private int ctx; 39 40 /** 41 * Holds a pointer to the native DSA key. 42 */ 43 private int dsa; 44 45 /** 46 * Holds a pointer to the native RSA key. 47 */ 48 private int rsa; 49 50 /** 51 * Holds the OpenSSL name of the algorithm (lower case, no dashes). 52 */ 53 private String evpAlgorithm; 54 55 /** 56 * Holds a dummy buffer for writing single bytes to the digest. 57 */ 58 private byte[] singleByte = new byte[1]; 59 60 /** 61 * Creates a new OpenSSLSignature instance for the given algorithm name. 62 * 63 * @param algorithm The name of the algorithm, e.g. "SHA1". 64 * 65 * @return The new OpenSSLSignature instance. 66 * 67 * @throws RuntimeException In case of problems. 68 */ 69 public static OpenSSLSignature getInstance(String algorithm) throws NoSuchAlgorithmException { 70 //log("OpenSSLSignature", "getInstance() invoked with " + algorithm); 71 return new OpenSSLSignature(algorithm); 72 } 73 74 /** 75 * Creates a new OpenSSLSignature instance for the given algorithm name. 76 * 77 * @param algorithm The name of the algorithm, e.g. "SHA1". 78 */ 79 private OpenSSLSignature(String algorithm) throws NoSuchAlgorithmException { 80 super(algorithm); 81 82 int i = algorithm.indexOf("with"); 83 if (i == -1) { 84 throw new NoSuchAlgorithmException(algorithm); 85 } 86 87 // We don't support MD2 anymore. This needs to also check for aliases 88 // and OIDs. 89 if ("MD2withRSA".equalsIgnoreCase(algorithm) || 90 "MD2withRSAEncryption".equalsIgnoreCase(algorithm) || 91 "1.2.840.113549.1.1.2".equalsIgnoreCase(algorithm) || 92 "MD2/RSA".equalsIgnoreCase(algorithm)) { 93 throw new NoSuchAlgorithmException("MD2withRSA"); 94 } 95 96 // For the special combination of DSA and SHA1, we need to pass the 97 // algorithm name as a pair consisting of crypto algorithm and hash 98 // algorithm. For all other (RSA) cases, passing the hash algorithm 99 // alone is not only sufficient, but actually necessary. OpenSSL 100 // doesn't accept something like RSA-SHA1. 101 if ("1.3.14.3.2.26with1.2.840.10040.4.1".equals(algorithm) 102 || "SHA1withDSA".equals(algorithm) 103 || "SHAwithDSA".equals(algorithm)) { 104 evpAlgorithm = "DSA-SHA"; 105 } else { 106 evpAlgorithm = algorithm.substring(0, i).replace("-", "").toUpperCase(); 107 } 108 109 ctx = NativeCrypto.EVP_new(); 110 } 111 112 @Override 113 protected void engineUpdate(byte input) { 114 singleByte[0] = input; 115 engineUpdate(singleByte, 0, 1); 116 } 117 118 @Override 119 protected void engineUpdate(byte[] input, int offset, int len) { 120 if (state == SIGN) { 121 throw new UnsupportedOperationException(); 122 } else { 123 NativeCrypto.EVP_VerifyUpdate(ctx, input, offset, len); 124 } 125 } 126 127 @Override 128 protected Object engineGetParameter(String param) throws InvalidParameterException { 129 return null; 130 } 131 132 @Override 133 protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { 134 throw new UnsupportedOperationException(); 135 } 136 137 @Override 138 protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { 139 //log("OpenSSLSignature", "engineInitVerify() invoked with " + publicKey.getClass().getCanonicalName()); 140 141 if (publicKey instanceof DSAPublicKey) { 142 try { 143 DSAPublicKey dsaPublicKey = (DSAPublicKey)publicKey; 144 DSAParams dsaParams = dsaPublicKey.getParams(); 145 dsa = NativeCrypto.EVP_PKEY_new_DSA(dsaParams.getP().toByteArray(), 146 dsaParams.getQ().toByteArray(), dsaParams.getG().toByteArray(), 147 dsaPublicKey.getY().toByteArray(), null); 148 149 } catch (Exception ex) { 150 throw new InvalidKeyException(ex.toString()); 151 } 152 } else if (publicKey instanceof RSAPublicKey) { 153 try { 154 RSAPublicKey rsaPublicKey = (RSAPublicKey)publicKey; 155 rsa = NativeCrypto.EVP_PKEY_new_RSA(rsaPublicKey.getModulus().toByteArray(), 156 rsaPublicKey.getPublicExponent().toByteArray(), null, null, null); 157 158 } catch (Exception ex) { 159 throw new InvalidKeyException(ex.toString()); 160 } 161 } else { 162 throw new InvalidKeyException("Need DSA or RSA public key"); 163 } 164 165 try { 166 NativeCrypto.EVP_VerifyInit(ctx, evpAlgorithm); 167 } catch (Exception ex) { 168 throw new RuntimeException(ex); 169 } 170 } 171 172 @Override 173 protected void engineSetParameter(String param, Object value) throws InvalidParameterException { 174 } 175 176 @Override 177 protected byte[] engineSign() throws SignatureException { 178 throw new UnsupportedOperationException(); 179 } 180 181 @Override 182 protected boolean engineVerify(byte[] sigBytes) throws SignatureException { 183 int handle = (rsa != 0) ? rsa : dsa; 184 185 if (handle == 0) { 186 // This can't actually happen, but you never know... 187 throw new SignatureException("Need DSA or RSA public key"); 188 } 189 190 try { 191 int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length, handle); 192 return result == 1; 193 } catch (Exception ex) { 194 throw new SignatureException(ex); 195 } 196 197 } 198 199 @Override 200 protected void finalize() throws Throwable { 201 super.finalize(); 202 203 if (dsa != 0) { 204 NativeCrypto.EVP_PKEY_free(dsa); 205 } 206 207 if (rsa != 0) { 208 NativeCrypto.EVP_PKEY_free(rsa); 209 } 210 211 if (ctx != 0) { 212 NativeCrypto.EVP_free(ctx); 213 } 214 } 215} 216