1/*
2 * Copyright (c) 2003, 2015, 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
26package sun.security.pkcs11;
27
28import java.security.*;
29import java.security.spec.AlgorithmParameterSpec;
30import java.security.spec.*;
31
32import java.util.Locale;
33
34import javax.crypto.*;
35import javax.crypto.spec.*;
36
37import static sun.security.pkcs11.TemplateManager.*;
38import sun.security.pkcs11.wrapper.*;
39import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
40import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
41import sun.security.util.KeyUtil;
42
43/**
44 * RSA Cipher implementation class. We currently only support
45 * PKCS#1 v1.5 padding on top of CKM_RSA_PKCS.
46 *
47 * @author  Andreas Sterbenz
48 * @since   1.5
49 */
50final class P11RSACipher extends CipherSpi {
51
52    // minimum length of PKCS#1 v1.5 padding
53    private final static int PKCS1_MIN_PADDING_LENGTH = 11;
54
55    // constant byte[] of length 0
56    private final static byte[] B0 = new byte[0];
57
58    // mode constant for public key encryption
59    private final static int MODE_ENCRYPT = 1;
60    // mode constant for private key decryption
61    private final static int MODE_DECRYPT = 2;
62    // mode constant for private key encryption (signing)
63    private final static int MODE_SIGN    = 3;
64    // mode constant for public key decryption (verifying)
65    private final static int MODE_VERIFY  = 4;
66
67    // padding type constant for NoPadding
68    private final static int PAD_NONE = 1;
69    // padding type constant for PKCS1Padding
70    private final static int PAD_PKCS1 = 2;
71
72    // token instance
73    private final Token token;
74
75    // algorithm name (always "RSA")
76    private final String algorithm;
77
78    // mechanism id
79    private final long mechanism;
80
81    // associated session, if any
82    private Session session;
83
84    // mode, one of MODE_* above
85    private int mode;
86
87    // padding, one of PAD_* above
88    private int padType;
89
90    private byte[] buffer;
91    private int bufOfs;
92
93    // key, if init() was called
94    private P11Key p11Key;
95
96    // flag indicating whether an operation is initialized
97    private boolean initialized;
98
99    // maximum input data size allowed
100    // for decryption, this is the length of the key
101    // for encryption, length of the key minus minimum padding length
102    private int maxInputSize;
103
104    // maximum output size. this is the length of the key
105    private int outputSize;
106
107    // cipher parameter for TLS RSA premaster secret
108    private AlgorithmParameterSpec spec = null;
109
110    // the source of randomness
111    private SecureRandom random;
112
113    P11RSACipher(Token token, String algorithm, long mechanism)
114            throws PKCS11Exception {
115        super();
116        this.token = token;
117        this.algorithm = "RSA";
118        this.mechanism = mechanism;
119    }
120
121    // modes do not make sense for RSA, but allow ECB
122    // see JCE spec
123    protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
124        if (mode.equalsIgnoreCase("ECB") == false) {
125            throw new NoSuchAlgorithmException("Unsupported mode " + mode);
126        }
127    }
128
129    protected void engineSetPadding(String padding)
130            throws NoSuchPaddingException {
131        String lowerPadding = padding.toLowerCase(Locale.ENGLISH);
132        if (lowerPadding.equals("pkcs1padding")) {
133            padType = PAD_PKCS1;
134        } else if (lowerPadding.equals("nopadding")) {
135            padType = PAD_NONE;
136        } else {
137            throw new NoSuchPaddingException("Unsupported padding " + padding);
138        }
139    }
140
141    // return 0 as block size, we are not a block cipher
142    // see JCE spec
143    protected int engineGetBlockSize() {
144        return 0;
145    }
146
147    // return the output size
148    // see JCE spec
149    protected int engineGetOutputSize(int inputLen) {
150        return outputSize;
151    }
152
153    // no IV, return null
154    // see JCE spec
155    protected byte[] engineGetIV() {
156        return null;
157    }
158
159    // no parameters, return null
160    // see JCE spec
161    protected AlgorithmParameters engineGetParameters() {
162        return null;
163    }
164
165    // see JCE spec
166    protected void engineInit(int opmode, Key key, SecureRandom random)
167            throws InvalidKeyException {
168        implInit(opmode, key);
169    }
170
171    // see JCE spec
172    @SuppressWarnings("deprecation")
173    protected void engineInit(int opmode, Key key,
174            AlgorithmParameterSpec params, SecureRandom random)
175            throws InvalidKeyException, InvalidAlgorithmParameterException {
176        if (params != null) {
177            if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
178                throw new InvalidAlgorithmParameterException(
179                        "Parameters not supported");
180            }
181            spec = params;
182            this.random = random;   // for TLS RSA premaster secret
183        }
184        implInit(opmode, key);
185    }
186
187    // see JCE spec
188    protected void engineInit(int opmode, Key key, AlgorithmParameters params,
189            SecureRandom random)
190            throws InvalidKeyException, InvalidAlgorithmParameterException {
191        if (params != null) {
192            throw new InvalidAlgorithmParameterException(
193                        "Parameters not supported");
194        }
195        implInit(opmode, key);
196    }
197
198    private void implInit(int opmode, Key key) throws InvalidKeyException {
199        cancelOperation();
200        p11Key = P11KeyFactory.convertKey(token, key, algorithm);
201        boolean encrypt;
202        if (opmode == Cipher.ENCRYPT_MODE) {
203            encrypt = true;
204        } else if (opmode == Cipher.DECRYPT_MODE) {
205            encrypt = false;
206        } else if (opmode == Cipher.WRAP_MODE) {
207            if (p11Key.isPublic() == false) {
208                throw new InvalidKeyException
209                                ("Wrap has to be used with public keys");
210            }
211            // No further setup needed for C_Wrap(). We'll initialize later if
212            // we can't use C_Wrap().
213            return;
214        } else if (opmode == Cipher.UNWRAP_MODE) {
215            if (p11Key.isPrivate() == false) {
216                throw new InvalidKeyException
217                                ("Unwrap has to be used with private keys");
218            }
219            // No further setup needed for C_Unwrap(). We'll initialize later
220            // if we can't use C_Unwrap().
221            return;
222        } else {
223            throw new InvalidKeyException("Unsupported mode: " + opmode);
224        }
225        if (p11Key.isPublic()) {
226            mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
227        } else if (p11Key.isPrivate()) {
228            mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
229        } else {
230            throw new InvalidKeyException("Unknown key type: " + p11Key);
231        }
232        int n = (p11Key.length() + 7) >> 3;
233        outputSize = n;
234        buffer = new byte[n];
235        maxInputSize = ((padType == PAD_PKCS1 && encrypt) ?
236                            (n - PKCS1_MIN_PADDING_LENGTH) : n);
237        try {
238            initialize();
239        } catch (PKCS11Exception e) {
240            throw new InvalidKeyException("init() failed", e);
241        }
242    }
243
244    private void cancelOperation() {
245        token.ensureValid();
246        if (initialized == false) {
247            return;
248        }
249        initialized = false;
250        if ((session == null) || (token.explicitCancel == false)) {
251            return;
252        }
253        if (session.hasObjects() == false) {
254            session = token.killSession(session);
255            return;
256        }
257        try {
258            PKCS11 p11 = token.p11;
259            int inLen = maxInputSize;
260            int outLen = buffer.length;
261            switch (mode) {
262            case MODE_ENCRYPT:
263                p11.C_Encrypt
264                        (session.id(), buffer, 0, inLen, buffer, 0, outLen);
265                break;
266            case MODE_DECRYPT:
267                p11.C_Decrypt
268                        (session.id(), buffer, 0, inLen, buffer, 0, outLen);
269                break;
270            case MODE_SIGN:
271                byte[] tmpBuffer = new byte[maxInputSize];
272                p11.C_Sign
273                        (session.id(), tmpBuffer);
274                break;
275            case MODE_VERIFY:
276                p11.C_VerifyRecover
277                        (session.id(), buffer, 0, inLen, buffer, 0, outLen);
278                break;
279            default:
280                throw new ProviderException("internal error");
281            }
282        } catch (PKCS11Exception e) {
283            // XXX ensure this always works, ignore error
284        }
285    }
286
287    private void ensureInitialized() throws PKCS11Exception {
288        token.ensureValid();
289        if (initialized == false) {
290            initialize();
291        }
292    }
293
294    private void initialize() throws PKCS11Exception {
295        if (session == null) {
296            session = token.getOpSession();
297        }
298        PKCS11 p11 = token.p11;
299        CK_MECHANISM ckMechanism = new CK_MECHANISM(mechanism);
300        switch (mode) {
301        case MODE_ENCRYPT:
302            p11.C_EncryptInit(session.id(), ckMechanism, p11Key.keyID);
303            break;
304        case MODE_DECRYPT:
305            p11.C_DecryptInit(session.id(), ckMechanism, p11Key.keyID);
306            break;
307        case MODE_SIGN:
308            p11.C_SignInit(session.id(), ckMechanism, p11Key.keyID);
309            break;
310        case MODE_VERIFY:
311            p11.C_VerifyRecoverInit(session.id(), ckMechanism, p11Key.keyID);
312            break;
313        default:
314            throw new AssertionError("internal error");
315        }
316        bufOfs = 0;
317        initialized = true;
318    }
319
320    private void implUpdate(byte[] in, int inOfs, int inLen) {
321        try {
322            ensureInitialized();
323        } catch (PKCS11Exception e) {
324            throw new ProviderException("update() failed", e);
325        }
326        if ((inLen == 0) || (in == null)) {
327            return;
328        }
329        if (bufOfs + inLen > maxInputSize) {
330            bufOfs = maxInputSize + 1;
331            return;
332        }
333        System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
334        bufOfs += inLen;
335    }
336
337    private int implDoFinal(byte[] out, int outOfs, int outLen)
338            throws BadPaddingException, IllegalBlockSizeException {
339        if (bufOfs > maxInputSize) {
340            throw new IllegalBlockSizeException("Data must not be longer "
341                + "than " + maxInputSize + " bytes");
342        }
343        try {
344            ensureInitialized();
345            PKCS11 p11 = token.p11;
346            int n;
347            switch (mode) {
348            case MODE_ENCRYPT:
349                n = p11.C_Encrypt
350                        (session.id(), buffer, 0, bufOfs, out, outOfs, outLen);
351                break;
352            case MODE_DECRYPT:
353                n = p11.C_Decrypt
354                        (session.id(), buffer, 0, bufOfs, out, outOfs, outLen);
355                break;
356            case MODE_SIGN:
357                byte[] tmpBuffer = new byte[bufOfs];
358                System.arraycopy(buffer, 0, tmpBuffer, 0, bufOfs);
359                tmpBuffer = p11.C_Sign(session.id(), tmpBuffer);
360                if (tmpBuffer.length > outLen) {
361                    throw new BadPaddingException(
362                        "Output buffer (" + outLen + ") is too small to " +
363                        "hold the produced data (" + tmpBuffer.length + ")");
364                }
365                System.arraycopy(tmpBuffer, 0, out, outOfs, tmpBuffer.length);
366                n = tmpBuffer.length;
367                break;
368            case MODE_VERIFY:
369                n = p11.C_VerifyRecover
370                        (session.id(), buffer, 0, bufOfs, out, outOfs, outLen);
371                break;
372            default:
373                throw new ProviderException("internal error");
374            }
375            return n;
376        } catch (PKCS11Exception e) {
377            throw (BadPaddingException)new BadPaddingException
378                ("doFinal() failed").initCause(e);
379        } finally {
380            initialized = false;
381            session = token.releaseSession(session);
382        }
383    }
384
385    // see JCE spec
386    protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
387        implUpdate(in, inOfs, inLen);
388        return B0;
389    }
390
391    // see JCE spec
392    protected int engineUpdate(byte[] in, int inOfs, int inLen,
393            byte[] out, int outOfs) throws ShortBufferException {
394        implUpdate(in, inOfs, inLen);
395        return 0;
396    }
397
398    // see JCE spec
399    protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
400            throws IllegalBlockSizeException, BadPaddingException {
401        implUpdate(in, inOfs, inLen);
402        int n = implDoFinal(buffer, 0, buffer.length);
403        byte[] out = new byte[n];
404        System.arraycopy(buffer, 0, out, 0, n);
405        return out;
406    }
407
408    // see JCE spec
409    protected int engineDoFinal(byte[] in, int inOfs, int inLen,
410            byte[] out, int outOfs) throws ShortBufferException,
411            IllegalBlockSizeException, BadPaddingException {
412        implUpdate(in, inOfs, inLen);
413        return implDoFinal(out, outOfs, out.length - outOfs);
414    }
415
416    private byte[] doFinal() throws BadPaddingException,
417            IllegalBlockSizeException {
418        byte[] t = new byte[2048];
419        int n = implDoFinal(t, 0, t.length);
420        byte[] out = new byte[n];
421        System.arraycopy(t, 0, out, 0, n);
422        return out;
423    }
424
425    // see JCE spec
426    protected byte[] engineWrap(Key key) throws InvalidKeyException,
427            IllegalBlockSizeException {
428        String keyAlg = key.getAlgorithm();
429        P11Key sKey = null;
430        try {
431            // The conversion may fail, e.g. trying to wrap an AES key on
432            // a token that does not support AES, or when the key size is
433            // not within the range supported by the token.
434            sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
435        } catch (InvalidKeyException ike) {
436            byte[] toBeWrappedKey = key.getEncoded();
437            if (toBeWrappedKey == null) {
438                throw new InvalidKeyException
439                        ("wrap() failed, no encoding available", ike);
440            }
441            // Directly encrypt the key encoding when key conversion failed
442            implInit(Cipher.ENCRYPT_MODE, p11Key);
443            implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);
444            try {
445                return doFinal();
446            } catch (BadPaddingException bpe) {
447                // should not occur
448                throw new InvalidKeyException("wrap() failed", bpe);
449            } finally {
450                // Restore original mode
451                implInit(Cipher.WRAP_MODE, p11Key);
452            }
453        }
454        Session s = null;
455        try {
456            s = token.getOpSession();
457            return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
458                p11Key.keyID, sKey.keyID);
459        } catch (PKCS11Exception e) {
460            throw new InvalidKeyException("wrap() failed", e);
461        } finally {
462            token.releaseSession(s);
463        }
464    }
465
466    // see JCE spec
467    @SuppressWarnings("deprecation")
468    protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
469            int type) throws InvalidKeyException, NoSuchAlgorithmException {
470
471        boolean isTlsRsaPremasterSecret =
472                algorithm.equals("TlsRsaPremasterSecret");
473        Exception failover = null;
474
475        // Should C_Unwrap be preferred for non-TLS RSA premaster secret?
476        if (token.supportsRawSecretKeyImport()) {
477            // XXX implement unwrap using C_Unwrap() for all keys
478            implInit(Cipher.DECRYPT_MODE, p11Key);
479            try {
480                if (wrappedKey.length > maxInputSize) {
481                    throw new InvalidKeyException("Key is too long for unwrapping");
482                }
483
484                byte[] encoded = null;
485                implUpdate(wrappedKey, 0, wrappedKey.length);
486                try {
487                    encoded = doFinal();
488                } catch (BadPaddingException e) {
489                    if (isTlsRsaPremasterSecret) {
490                        failover = e;
491                    } else {
492                        throw new InvalidKeyException("Unwrapping failed", e);
493                    }
494                } catch (IllegalBlockSizeException e) {
495                    // should not occur, handled with length check above
496                    throw new InvalidKeyException("Unwrapping failed", e);
497                }
498
499                if (isTlsRsaPremasterSecret) {
500                    if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
501                        throw new IllegalStateException(
502                                "No TlsRsaPremasterSecretParameterSpec specified");
503                    }
504
505                    // polish the TLS premaster secret
506                    TlsRsaPremasterSecretParameterSpec psps =
507                            (TlsRsaPremasterSecretParameterSpec)spec;
508                    encoded = KeyUtil.checkTlsPreMasterSecretKey(
509                            psps.getClientVersion(), psps.getServerVersion(),
510                            random, encoded, (failover != null));
511                }
512
513                return ConstructKeys.constructKey(encoded, algorithm, type);
514            } finally {
515                // Restore original mode
516                implInit(Cipher.UNWRAP_MODE, p11Key);
517            }
518        } else {
519            Session s = null;
520            SecretKey secretKey = null;
521            try {
522                try {
523                    s = token.getObjSession();
524                    long keyType = CKK_GENERIC_SECRET;
525                    CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
526                            new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
527                            new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
528                        };
529                    attributes = token.getAttributes(
530                            O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
531                    long keyID = token.p11.C_UnwrapKey(s.id(),
532                            new CK_MECHANISM(mechanism), p11Key.keyID,
533                            wrappedKey, attributes);
534                    secretKey = P11Key.secretKey(s, keyID,
535                            algorithm, 48 << 3, attributes);
536                } catch (PKCS11Exception e) {
537                    if (isTlsRsaPremasterSecret) {
538                        failover = e;
539                    } else {
540                        throw new InvalidKeyException("unwrap() failed", e);
541                    }
542                }
543
544                if (isTlsRsaPremasterSecret) {
545                    TlsRsaPremasterSecretParameterSpec psps =
546                            (TlsRsaPremasterSecretParameterSpec)spec;
547
548                    // Please use the tricky failover as the parameter so that
549                    // smart compiler won't dispose the unused variable.
550                    secretKey = polishPreMasterSecretKey(token, s,
551                            failover, secretKey,
552                            psps.getClientVersion(), psps.getServerVersion());
553                }
554
555                return secretKey;
556            } finally {
557                token.releaseSession(s);
558            }
559        }
560    }
561
562    // see JCE spec
563    protected int engineGetKeySize(Key key) throws InvalidKeyException {
564        int n = P11KeyFactory.convertKey(token, key, algorithm).length();
565        return n;
566    }
567
568    private static SecretKey polishPreMasterSecretKey(
569            Token token, Session session,
570            Exception failover, SecretKey unwrappedKey,
571            int clientVersion, int serverVersion) {
572
573        SecretKey newKey;
574        CK_VERSION version = new CK_VERSION(
575                (clientVersion >>> 8) & 0xFF, clientVersion & 0xFF);
576        try {
577            CK_ATTRIBUTE[] attributes = token.getAttributes(
578                    O_GENERATE, CKO_SECRET_KEY,
579                    CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]);
580            long keyID = token.p11.C_GenerateKey(session.id(),
581                    new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version),
582                    attributes);
583            newKey = P11Key.secretKey(session,
584                    keyID, "TlsRsaPremasterSecret", 48 << 3, attributes);
585        } catch (PKCS11Exception e) {
586            throw new ProviderException(
587                    "Could not generate premaster secret", e);
588        }
589
590        return (failover == null) ? unwrappedKey : newKey;
591    }
592
593}
594
595final class ConstructKeys {
596    /**
597     * Construct a public key from its encoding.
598     *
599     * @param encodedKey the encoding of a public key.
600     *
601     * @param encodedKeyAlgorithm the algorithm the encodedKey is for.
602     *
603     * @return a public key constructed from the encodedKey.
604     */
605    private static final PublicKey constructPublicKey(byte[] encodedKey,
606            String encodedKeyAlgorithm)
607            throws InvalidKeyException, NoSuchAlgorithmException {
608        try {
609            KeyFactory keyFactory =
610                KeyFactory.getInstance(encodedKeyAlgorithm);
611            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
612            return keyFactory.generatePublic(keySpec);
613        } catch (NoSuchAlgorithmException nsae) {
614            throw new NoSuchAlgorithmException("No installed providers " +
615                                               "can create keys for the " +
616                                               encodedKeyAlgorithm +
617                                               "algorithm", nsae);
618        } catch (InvalidKeySpecException ike) {
619            throw new InvalidKeyException("Cannot construct public key", ike);
620        }
621    }
622
623    /**
624     * Construct a private key from its encoding.
625     *
626     * @param encodedKey the encoding of a private key.
627     *
628     * @param encodedKeyAlgorithm the algorithm the wrapped key is for.
629     *
630     * @return a private key constructed from the encodedKey.
631     */
632    private static final PrivateKey constructPrivateKey(byte[] encodedKey,
633            String encodedKeyAlgorithm) throws InvalidKeyException,
634            NoSuchAlgorithmException {
635        try {
636            KeyFactory keyFactory =
637                KeyFactory.getInstance(encodedKeyAlgorithm);
638            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
639            return keyFactory.generatePrivate(keySpec);
640        } catch (NoSuchAlgorithmException nsae) {
641            throw new NoSuchAlgorithmException("No installed providers " +
642                                               "can create keys for the " +
643                                               encodedKeyAlgorithm +
644                                               "algorithm", nsae);
645        } catch (InvalidKeySpecException ike) {
646            throw new InvalidKeyException("Cannot construct private key", ike);
647        }
648    }
649
650    /**
651     * Construct a secret key from its encoding.
652     *
653     * @param encodedKey the encoding of a secret key.
654     *
655     * @param encodedKeyAlgorithm the algorithm the secret key is for.
656     *
657     * @return a secret key constructed from the encodedKey.
658     */
659    private static final SecretKey constructSecretKey(byte[] encodedKey,
660            String encodedKeyAlgorithm) {
661        return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);
662    }
663
664    static final Key constructKey(byte[] encoding, String keyAlgorithm,
665            int keyType) throws InvalidKeyException, NoSuchAlgorithmException {
666        switch (keyType) {
667        case Cipher.SECRET_KEY:
668            return constructSecretKey(encoding, keyAlgorithm);
669        case Cipher.PRIVATE_KEY:
670            return constructPrivateKey(encoding, keyAlgorithm);
671        case Cipher.PUBLIC_KEY:
672            return constructPublicKey(encoding, keyAlgorithm);
673        default:
674            throw new InvalidKeyException("Unknown keytype " + keyType);
675        }
676    }
677}
678