summaryrefslogtreecommitdiffstats
path: root/base/util/src/netscape/security/x509/CertAndKeyGen.java
blob: 1579d46bf2286d946dae9ded7d323149b6e9cb63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This program 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 for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// (C) 2007 Red Hat, Inc.
// All rights reserved.
// --- END COPYRIGHT BLOCK ---
package netscape.security.x509;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;

import netscape.security.pkcs.PKCS10;

/**
 * Generate a pair of keys, and provide access to them. This class is
 * provided primarily for ease of use.
 * 
 * <P>
 * This provides some simple certificate management functionality. Specifically, it allows you to create self-signed
 * X.509 certificates as well as PKCS 10 based certificate signing requests.
 * 
 * <P>
 * Keys for some public key signature algorithms have algorithm parameters, such as DSS/DSA. Some sites' Certificate
 * Authorities adopt fixed algorithm parameters, which speeds up some operations including key generation and signing.
 * <em>At this time, this interface
 * does not provide a way to provide such algorithm parameters, e.g.
 * by providing the CA certificate which includes those parameters.</em>
 * 
 * <P>
 * Also, note that at this time only signature-capable keys may be acquired through this interface. Diffie-Hellman keys,
 * used for secure key exchange, may be supported later.
 * 
 * @author David Brownell
 * @author Hemma Prafullchandra
 * @version 1.44
 * @see PKCS10
 * @see X509CertImpl
 */
public final class CertAndKeyGen {
    /**
     * Creates a CertAndKeyGen object for a particular key type
     * and signature algorithm.
     * 
     * @param keyType type of key, e.g. "RSA", "DSA"
     * @param sigAlg name of the signature algorithm, e.g. "MD5WithRSA",
     *            "MD2WithRSA", "SHAwithDSA".
     * @exception NoSuchAlgorithmException on unrecognized algorithms.
     */
    public CertAndKeyGen(String keyType, String sigAlg)
            throws NoSuchAlgorithmException {
        keyGen = KeyPairGenerator.getInstance(keyType);
        this.sigAlg = sigAlg;
    }

    /**
     * Sets the source of random numbers used when generating keys.
     * If you do not provide one, a system default facility is used.
     * You may wish to provide your own source of random numbers
     * to get a reproducible sequence of keys and signatures, or
     * because you may be able to take advantage of strong sources
     * of randomness/entropy in your environment.
     * 
     * @deprecated All random numbers come from PKCS #11 now.
     */
    public void setRandom(SecureRandom generator) {
    }

    // want "public void generate (X509Certificate)" ... inherit DSA/D-H param

    /**
     * Generates a random public/private key pair, with a given key
     * size. Different algorithms provide different degrees of security
     * for the same key size, because of the "work factor" involved in
     * brute force attacks. As computers become faster, it becomes
     * easier to perform such attacks. Small keys are to be avoided.
     * 
     * <P>
     * Note that not all values of "keyBits" are valid for all algorithms, and not all public key algorithms are
     * currently supported for use in X.509 certificates. If the algorithm you specified does not produce X.509
     * compatible keys, an invalid key exception is thrown.
     * 
     * @param keyBits the number of bits in the keys.
     * @exception InvalidKeyException if the environment does not
     *                provide X.509 public keys for this signature algorithm.
     */
    public void generate(int keyBits)
            throws InvalidKeyException {
        KeyPair pair;

        try {
            keyGen.initialize(keyBits);
            pair = keyGen.generateKeyPair();

        } catch (Exception e) {
            throw new IllegalArgumentException(e.getMessage());
        }

        PublicKey publicKey = pair.getPublic();

        if (publicKey instanceof X509Key) {
            this.publicKey = (X509Key) publicKey;

        } else {
            throw new InvalidKeyException("public key " + publicKey +
                      " not an X509Key.");
        }
        privateKey = pair.getPrivate();
    }

    /**
     * Returns the public key of the generated key pair.
     */
    public X509Key getPublicKey() {
        return publicKey;
    }

    /**
     * Returns the private key of the generated key pair.
     * 
     * <P>
     * <STRONG><em>Be extremely careful when handling private keys.
     * When private keys are not kept secret, they lose their ability
     * to securely authenticate specific entities ... that is a huge
     * security risk!</em></STRONG>
     */
    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    /**
     * Returns a self-signed X.509v1 certificate for the public key.
     * The certificate is immediately valid.
     * 
     * <P>
     * Such certificates normally are used to identify a "Certificate Authority" (CA). Accordingly, they will not always
     * be accepted by other parties. However, such certificates are also useful when you are bootstrapping your security
     * infrastructure, or deploying system prototypes.
     * 
     * @deprecated Use the new <a href =
     *             "#getSelfCertificate(netscape.security.x509.X500Name, long)">
     * 
     * @param myname X.500 name of the subject (who is also the issuer)
     * @param validity how long the certificate should be valid, in seconds
     */
    public X509Cert getSelfCert(X500Name myname, long validity)
            throws InvalidKeyException, SignatureException, NoSuchAlgorithmException {
        X509Certificate cert;

        try {
            cert = getSelfCertificate(myname, validity);
            return new X509Cert(cert.getEncoded());
        } catch (CertificateException e) {
            throw new SignatureException(e.getMessage());
        } catch (NoSuchProviderException e) {
            throw new NoSuchAlgorithmException(e.getMessage());
        } catch (IOException e) {
            throw new SignatureException(e.getMessage());
        }
    }

    /**
     * Returns a self-signed X.509v3 certificate for the public key.
     * The certificate is immediately valid. No extensions.
     * 
     * <P>
     * Such certificates normally are used to identify a "Certificate Authority" (CA). Accordingly, they will not always
     * be accepted by other parties. However, such certificates are also useful when you are bootstrapping your security
     * infrastructure, or deploying system prototypes.
     * 
     * @param myname X.500 name of the subject (who is also the issuer)
     * @param validity how long the certificate should be valid, in seconds
     * @exception CertificateException on certificate handling errors.
     * @exception InvalidKeyException on key handling errors.
     * @exception SignatureException on signature handling errors.
     * @exception NoSuchAlgorithmException on unrecognized algorithms.
     * @exception NoSuchProviderException on unrecognized providers.
     */
    public X509Certificate getSelfCertificate(X500Name myname, long validity)
            throws CertificateException, InvalidKeyException, SignatureException,
            NoSuchAlgorithmException, NoSuchProviderException {
        X500Signer issuer;
        X509CertImpl cert;
        Date firstDate, lastDate;

        try {
            issuer = getSigner(myname);

            firstDate = new Date();
            lastDate = new Date();
            lastDate.setTime(lastDate.getTime() + validity * 1000);

            CertificateValidity interval =
                                   new CertificateValidity(firstDate, lastDate);

            X509CertInfo info = new X509CertInfo();
            // Add all mandatory attributes
            info.set(X509CertInfo.VERSION,
                     new CertificateVersion(CertificateVersion.V1));
            info.set(X509CertInfo.SERIAL_NUMBER,
                    new CertificateSerialNumber((int) (firstDate.getTime() / 1000)));
            AlgorithmId algID = issuer.getAlgorithmId();
            info.set(X509CertInfo.ALGORITHM_ID,
                     new CertificateAlgorithmId(algID));
            info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(myname));
            info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
            info.set(X509CertInfo.VALIDITY, interval);
            info.set(X509CertInfo.ISSUER,
                     new CertificateIssuerName(issuer.getSigner()));

            cert = new X509CertImpl(info);
            cert.sign(privateKey, algID.getName());

            return (X509Certificate) cert;

        } catch (IOException e) {
            throw new CertificateEncodingException("getSelfCert: " +
                                                    e.getMessage());
        }
    }

    /**
     * Returns a PKCS #10 certificate request. The caller uses either <code>PKCS10.print</code> or
     * <code>PKCS10.toByteArray</code> operations on the result, to get the request in an appropriate
     * transmission format.
     * 
     * <P>
     * PKCS #10 certificate requests are sent, along with some proof of identity, to Certificate Authorities (CAs) which
     * then issue X.509 public key certificates.
     * 
     * @param myname X.500 name of the subject
     * @exception InvalidKeyException on key handling errors.
     * @exception SignatureException on signature handling errors.
     */
    public PKCS10 getCertRequest(X500Name myname)
            throws InvalidKeyException, SignatureException {
        PKCS10 req = new PKCS10(publicKey);

        try {
            req.encodeAndSign(getSigner(myname));

        } catch (CertificateException e) {
            throw new SignatureException(sigAlg + " CertificateException");

        } catch (IOException e) {
            throw new SignatureException(sigAlg + " IOException");

        } catch (NoSuchAlgorithmException e) {
            // "can't happen"
            throw new SignatureException(sigAlg + " unavailable?");
        }
        return req;
    }

    private X500Signer getSigner(X500Name me)
            throws InvalidKeyException, NoSuchAlgorithmException {
        Signature signature = Signature.getInstance(sigAlg);

        signature.initSign(privateKey);
        return new X500Signer(signature, me);
    }

    private String sigAlg;
    private KeyPairGenerator keyGen;
    private X509Key publicKey;
    private PrivateKey privateKey;
}