1 /* 2 * Copyright (C) 2012 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.RSAPrivateCrtKey; 27 import java.security.interfaces.RSAPrivateKey; 28 import java.security.interfaces.RSAPublicKey; 29 import java.util.Arrays; 30 31 /** 32 * Implements the JDK Signature interface needed for RAW RSA signature 33 * generation and verification using OpenSSL. 34 */ 35 public class OpenSSLSignatureRawRSA extends Signature { 36 /** 37 * The current OpenSSL key we're operating on. 38 */ 39 private OpenSSLKey key; 40 41 /** 42 * Buffer to hold value to be signed or verified. 43 */ 44 private byte[] inputBuffer; 45 46 /** 47 * Current offset in input buffer. 48 */ 49 private int inputOffset; 50 51 /** 52 * Provides a flag to specify when the input is too long. 53 */ 54 private boolean inputIsTooLong; 55 56 /** 57 * Creates a new OpenSSLSignature instance for the given algorithm name. 58 */ 59 public OpenSSLSignatureRawRSA() throws NoSuchAlgorithmException { 60 super("NONEwithRSA"); 61 } 62 63 @Override 64 protected void engineUpdate(byte input) { 65 final int oldOffset = inputOffset++; 66 67 if (inputOffset > inputBuffer.length) { 68 inputIsTooLong = true; 69 return; 70 } 71 72 inputBuffer[oldOffset] = input; 73 } 74 75 @Override 76 protected void engineUpdate(byte[] input, int offset, int len) { 77 final int oldOffset = inputOffset; 78 inputOffset += len; 79 80 if (inputOffset > inputBuffer.length) { 81 inputIsTooLong = true; 82 return; 83 } 84 85 System.arraycopy(input, offset, inputBuffer, oldOffset, len); 86 } 87 88 @Override 89 protected Object engineGetParameter(String param) throws InvalidParameterException { 90 return null; 91 } 92 93 @Override 94 protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { 95 if (privateKey instanceof OpenSSLRSAPrivateKey) { 96 OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) privateKey; 97 key = rsaPrivateKey.getOpenSSLKey(); 98 } else if (privateKey instanceof RSAPrivateCrtKey) { 99 RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey; 100 key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey); 101 } else if (privateKey instanceof RSAPrivateKey) { 102 RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey; 103 key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey); 104 } else { 105 throw new InvalidKeyException("Need DSA or RSA private key"); 106 } 107 108 // Allocate buffer according to RSA modulus size. 109 int maxSize = NativeCrypto.RSA_size(key.getPkeyContext()); 110 inputBuffer = new byte[maxSize]; 111 inputOffset = 0; 112 } 113 114 @Override 115 protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { 116 if (publicKey instanceof OpenSSLRSAPublicKey) { 117 OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) publicKey; 118 key = rsaPublicKey.getOpenSSLKey(); 119 } else if (publicKey instanceof RSAPublicKey) { 120 RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; 121 key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey); 122 } else { 123 throw new InvalidKeyException("Need DSA or RSA public key"); 124 } 125 126 // Allocate buffer according to RSA modulus size. 127 int maxSize = NativeCrypto.RSA_size(key.getPkeyContext()); 128 inputBuffer = new byte[maxSize]; 129 inputOffset = 0; 130 } 131 132 @Override 133 protected void engineSetParameter(String param, Object value) throws InvalidParameterException { 134 } 135 136 @Override 137 protected byte[] engineSign() throws SignatureException { 138 if (key == null) { 139 // This can't actually happen, but you never know... 140 throw new SignatureException("Need RSA private key"); 141 } 142 143 if (inputIsTooLong) { 144 throw new SignatureException("input length " + inputOffset + " != " 145 + inputBuffer.length + " (modulus size)"); 146 } 147 148 byte[] outputBuffer = new byte[inputBuffer.length]; 149 try { 150 NativeCrypto.RSA_private_encrypt(inputOffset, inputBuffer, outputBuffer, 151 key.getPkeyContext(), NativeCrypto.RSA_PKCS1_PADDING); 152 return outputBuffer; 153 } catch (Exception ex) { 154 throw new SignatureException(ex); 155 } finally { 156 inputOffset = 0; 157 } 158 } 159 160 @Override 161 protected boolean engineVerify(byte[] sigBytes) throws SignatureException { 162 if (key == null) { 163 // This can't actually happen, but you never know... 164 throw new SignatureException("Need RSA public key"); 165 } 166 167 if (inputIsTooLong) { 168 return false; 169 } 170 171 byte[] outputBuffer = new byte[inputBuffer.length]; 172 try { 173 final int resultSize; 174 try { 175 resultSize = NativeCrypto.RSA_public_decrypt(sigBytes.length, sigBytes, 176 outputBuffer, key.getPkeyContext(), NativeCrypto.RSA_PKCS1_PADDING); 177 } catch (SignatureException e) { 178 throw e; 179 } catch (Exception e) { 180 return false; 181 } 182 /* Make this constant time by comparing every byte. */ 183 boolean matches = (resultSize == inputOffset); 184 for (int i = 0; i < resultSize; i++) { 185 if (inputBuffer[i] != outputBuffer[i]) { 186 matches = false; 187 } 188 } 189 return matches; 190 } catch (Exception ex) { 191 throw new SignatureException(ex); 192 } finally { 193 inputOffset = 0; 194 } 195 } 196 } 197