Home | History | Annotate | Download | only in jsse
      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