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