jdk/src/java.base/share/classes/sun/security/provider/NamedKeyPairGenerator.java
2024-10-11 21:16:41 +00:00

178 lines
8.3 KiB
Java

/*
* 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);
}