1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.rsa;
  27 
  28 import java.io.IOException;
  29 import java.math.BigInteger;
  30 
  31 import java.security.*;
  32 import java.security.spec.*;
  33 import java.security.interfaces.*;
  34 
  35 import sun.security.util.*;
  36 import sun.security.x509.X509Key;
  37 import sun.security.x509.AlgorithmId;
  38 
  39 import static sun.security.rsa.RSAUtil.KeyType;
  40 
  41 /**
  42  * RSA public key implementation for "RSA", "RSASSA-PSS" algorithms.
  43  *
  44  * Note: RSA keys must be at least 512 bits long
  45  *
  46  * @see RSAPrivateCrtKeyImpl
  47  * @see RSAPrivateKeyImpl
  48  * @see RSAKeyFactory
  49  *
  50  * @since   1.5
  51  * @author  Andreas Sterbenz
  52  */
  53 public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey {
  54 
  55     private static final long serialVersionUID = 2644735423591199609L;
  56     private static final BigInteger THREE = BigInteger.valueOf(3);
  57 
  58     private BigInteger n;       // modulus
  59     private BigInteger e;       // public exponent
  60 
  61     // optional parameters associated with this RSA key
  62     // specified in the encoding of its AlgorithmId
  63     // must be null for "RSA" keys.
  64     private AlgorithmParameterSpec keyParams;
  65 
  66     /**
  67      * Generate a new RSAPublicKey from the specified encoding.
  68      * Used by SunPKCS11 provider.
  69      */
  70     public static RSAPublicKey newKey(byte[] encoded)
  71             throws InvalidKeyException {
  72         return new RSAPublicKeyImpl(encoded);
  73     }
  74 
  75     /**
  76      * Generate a new RSAPublicKey from the specified type and components.
  77      * Used by SunPKCS11 provider.
  78      */
  79     public static RSAPublicKey newKey(KeyType type,
  80             AlgorithmParameterSpec params, BigInteger n, BigInteger e)
  81             throws InvalidKeyException {
  82         AlgorithmId rsaId = RSAUtil.createAlgorithmId(type, params);
  83         return new RSAPublicKeyImpl(rsaId, n, e);
  84     }
  85 
  86     /**
  87      * Construct a RSA key from AlgorithmId and its components. Used by
  88      * RSAKeyFactory and RSAKeyPairGenerator.
  89      */
  90     RSAPublicKeyImpl(AlgorithmId rsaId, BigInteger n, BigInteger e)
  91             throws InvalidKeyException {
  92         RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
  93         checkExponentRange(n, e);
  94 
  95         this.n = n;
  96         this.e = e;
  97         this.keyParams = RSAUtil.getParamSpec(rsaId);
  98 
  99         // generate the encoding
 100         algid = rsaId;
 101         try {
 102             DerOutputStream out = new DerOutputStream();
 103             out.putInteger(n);
 104             out.putInteger(e);
 105             byte[] keyArray =
 106                 new DerValue(DerValue.tag_Sequence,
 107                              out.toByteArray()).toByteArray();
 108             setKey(new BitArray(keyArray.length*8, keyArray));
 109         } catch (IOException exc) {
 110             // should never occur
 111             throw new InvalidKeyException(exc);
 112         }
 113     }
 114 
 115     /**
 116      * Construct a key from its encoding. Used by RSAKeyFactory.
 117      */
 118     RSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
 119         decode(encoded); // this sets n and e value
 120         RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
 121         checkExponentRange(n, e);
 122 
 123         try {
 124             // this will check the validity of params
 125             this.keyParams = RSAUtil.getParamSpec(algid);
 126         } catch (ProviderException e) {
 127             throw new InvalidKeyException(e);
 128         }
 129     }
 130 
 131     // pkg private utility method for checking RSA modulus and public exponent
 132     static void checkExponentRange(BigInteger mod, BigInteger exp)
 133             throws InvalidKeyException {
 134         // the exponent should be smaller than the modulus
 135         if (exp.compareTo(mod) >= 0) {
 136             throw new InvalidKeyException("exponent is larger than modulus");
 137         }
 138 
 139         // the exponent should be at least 3
 140         if (exp.compareTo(THREE) < 0) {
 141             throw new InvalidKeyException("exponent is smaller than 3");
 142         }
 143     }
 144 
 145     // see JCA doc
 146     @Override
 147     public String getAlgorithm() {
 148         return algid.getName();
 149     }
 150 
 151     // see JCA doc
 152     @Override
 153     public BigInteger getModulus() {
 154         return n;
 155     }
 156 
 157     // see JCA doc
 158     @Override
 159     public BigInteger getPublicExponent() {
 160         return e;
 161     }
 162 
 163     // see JCA doc
 164     @Override
 165     public AlgorithmParameterSpec getParams() {
 166         return keyParams;
 167     }
 168 
 169     /**
 170      * Parse the key. Called by X509Key.
 171      */
 172     protected void parseKeyBits() throws InvalidKeyException {
 173         try {
 174             DerInputStream in = new DerInputStream(getKey().toByteArray());
 175             DerValue derValue = in.getDerValue();
 176             if (derValue.tag != DerValue.tag_Sequence) {
 177                 throw new IOException("Not a SEQUENCE");
 178             }
 179             DerInputStream data = derValue.data;
 180             n = data.getPositiveBigInteger();
 181             e = data.getPositiveBigInteger();
 182             if (derValue.data.available() != 0) {
 183                 throw new IOException("Extra data available");
 184             }
 185         } catch (IOException e) {
 186             throw new InvalidKeyException("Invalid RSA public key", e);
 187         }
 188     }
 189 
 190     // return a string representation of this key for debugging
 191     @Override
 192     public String toString() {
 193         return "Sun " + getAlgorithm() + " public key, " + n.bitLength()
 194                + " bits" + "\n  params: " + keyParams + "\n  modulus: " + n
 195                + "\n  public exponent: " + e;
 196     }
 197 
 198     protected Object writeReplace() throws java.io.ObjectStreamException {
 199         return new KeyRep(KeyRep.Type.PUBLIC,
 200                         getAlgorithm(),
 201                         getFormat(),
 202                         getEncoded());
 203     }
 204 }