/* * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.provider; import sun.security.pkcs.NamedPKCS8Key; import sun.security.x509.NamedX509Key; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; import java.security.KeyPair; import java.security.KeyPairGeneratorSpi; import java.security.ProviderException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.NamedParameterSpec; import java.util.Objects; /// A base class for all `KeyPairGenerator` implementations that can be /// configured with a named parameter set. /// /// Together with [NamedKeyFactory], [NamedKEM], and [NamedSignature], these /// classes form a compact framework designed to support any public key /// algorithm standardized with named parameter sets. In this scenario, /// the algorithm name is the "family name" and each standardized parameter /// set has a "parameter set name". Implementations of these classes are able /// to instantiate a `KeyPairGenerator`, `KeyFactory`, or `KEM` or `Signature` /// object using either the family name or a parameter set name. All keys used /// in this context will be of the type [NamedPKCS8Key] or [NamedX509Key], /// with `getAlgorithm` returning the family name, and `getParams` returning /// the parameter set name as a [NamedParameterSpec] object. /// /// An implementation must include a zero-argument public constructor that /// calls `super(fname, pnames)`, where `fname` is the family name of the /// algorithm and `pnames` are its supported parameter set names. `pnames` /// must contain at least one element. For an implementation of /// `NamedKeyPairGenerator`, the first element becomes its default parameter /// set, i.e. the parameter set to be used in key pair generation unless /// [#initialize(AlgorithmParameterSpec, java.security.SecureRandom)] /// is called on a different parameter set. /// /// An implementation must implement all abstract methods. For all these /// methods, the implementation must relinquish any "ownership" of any input /// and output array argument. Precisely, the implementation must not retain /// any reference to a returning array so that it won't be able to modify its /// content later. Similarly, the implementation must not modify any input /// array argument and must not retain any reference to an input array argument /// after the call. /// /// Also, an implementation must not keep any extra copy of a private key. /// For key generation, the only copy is the one returned in the /// [#implGenerateKeyPair] call. For all other methods, it must not make /// a copy of the input private key. A `KEM` implementation also must not /// keep a copy of the shared secret key, no matter if it's an encapsulator /// or a decapsulator. Only the code that owns these sensitive data can /// choose to perform cleanup when it determines they are no longer needed. /// /// The `NamedSignature` and `NamedKEM` classes provide `implCheckPublicKey` /// and `implCheckPrivateKey` methods that allow an implementation to validate /// a key before using it. An implementation may return a parsed key in /// a local type, and this parsed key will be passed to an operational method /// (For example, `implSign`) later. An implementation must not retain /// a reference of the parsed key. /// /// When constructing a [NamedX509Key] or [NamedPKCS8Key] object from raw key /// bytes, the key bytes are directly referenced within the object, so the /// caller must not modify them afterward. Similarly, the key's `getRawBytes` /// method returns direct references to the underlying raw key bytes, meaning /// the caller must not alter the contents of the returned value. /// /// Together, these measures ensure the classes are as efficient as possible, /// preventing unnecessary array cloning and potential data leaks. While these /// classes should not be considered immutable, strictly adhering to the rules /// above will ensure data integrity is maintained. /// /// Note: A limitation of `NamedKeyPairGenerator` and `NamedKeyFactory` is /// that the keys generated by their implementations will always be of type /// `NamedX509Key` or `NamedPKCS8Key`. Existing implementations of algorithms /// like EdDSA and XDH have been generating keys implementing `EdECKey` or /// `XECKey` interfaces, and they are not rewritten with this framework. /// `NamedParameterSpec` fields not implemented with this framework include /// Ed25519, Ed448, X25519, and X448. public abstract class NamedKeyPairGenerator extends KeyPairGeneratorSpi { private final String fname; // family name private final String[] pnames; // allowed parameter set name (at least one) protected String name; // init as private SecureRandom secureRandom; /// Creates a new `NamedKeyPairGenerator` object. /// /// @param fname the family name /// @param pnames supported parameter set names, at least one is needed. /// If multiple, the first one becomes the default parameter set name. protected NamedKeyPairGenerator(String fname, String... pnames) { if (fname == null) { throw new AssertionError("fname cannot be null"); } if (pnames == null || pnames.length == 0) { throw new AssertionError("pnames cannot be null or empty"); } this.fname = fname; this.pnames = pnames; } private String checkName(String name) throws InvalidAlgorithmParameterException { for (var pname : pnames) { if (pname.equalsIgnoreCase(name)) { // return the stored standard name return pname; } } throw new InvalidAlgorithmParameterException( "Unsupported parameter set name: " + name); } @Override public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { if (params instanceof NamedParameterSpec spec) { name = checkName(spec.getName()); } else { throw new InvalidAlgorithmParameterException( "Unsupported AlgorithmParameterSpec: " + params); } this.secureRandom = random; } @Override public void initialize(int keysize, SecureRandom random) { if (keysize != -1) { // User can call initialize(-1, sr) to provide a SecureRandom // without touching the parameter set currently used throw new InvalidParameterException("keysize not supported"); } this.secureRandom = random; } @Override public KeyPair generateKeyPair() { String pname = name != null ? name : pnames[0]; var keys = implGenerateKeyPair(pname, secureRandom); return new KeyPair(new NamedX509Key(fname, pname, keys[0]), new NamedPKCS8Key(fname, pname, keys[1])); } /// User-defined key pair generator. /// /// @param pname parameter set name /// @param sr `SecureRandom` object, `null` if not initialized /// @return public key and private key (in this order) in raw bytes /// @throws ProviderException if there is an internal error protected abstract byte[][] implGenerateKeyPair(String pname, SecureRandom sr); }