OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [tools/] [gnu/] [classpath/] [tools/] [jarsigner/] [SFHelper.java] - Blame information for rev 779

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 779 jeremybenn
/* SFHelper -- A .SF file helper
2
   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package gnu.classpath.tools.jarsigner;
40
 
41
import gnu.classpath.Configuration;
42
import gnu.java.security.OID;
43
import gnu.java.security.Registry;
44
import gnu.java.security.der.DER;
45
import gnu.java.security.der.DERValue;
46
import gnu.java.security.pkcs.PKCS7Data;
47
import gnu.java.security.pkcs.PKCS7SignedData;
48
import gnu.java.security.pkcs.SignerInfo;
49
import gnu.java.security.sig.ISignature;
50
import gnu.java.security.sig.ISignatureCodec;
51
import gnu.java.security.sig.dss.DSSSignature;
52
import gnu.java.security.sig.dss.DSSSignatureX509Codec;
53
import gnu.java.security.sig.rsa.RSAPKCS1V1_5Signature;
54
import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec;
55
import gnu.java.security.util.Util;
56
import gnu.java.util.jar.JarUtils;
57
 
58
import java.io.ByteArrayOutputStream;
59
import java.io.IOException;
60
import java.io.InputStream;
61
import java.math.BigInteger;
62
import java.security.PrivateKey;
63
import java.security.cert.CRLException;
64
import java.security.cert.Certificate;
65
import java.security.cert.CertificateEncodingException;
66
import java.security.cert.CertificateExpiredException;
67
import java.security.cert.CertificateNotYetValidException;
68
import java.security.cert.X509CRL;
69
import java.security.interfaces.DSAPrivateKey;
70
import java.security.interfaces.RSAPrivateKey;
71
import java.util.ArrayList;
72
import java.util.Date;
73
import java.util.HashMap;
74
import java.util.HashSet;
75
import java.util.List;
76
import java.util.Map;
77
import java.util.Set;
78
import java.util.jar.Attributes;
79
import java.util.jar.JarEntry;
80
import java.util.jar.JarFile;
81
import java.util.jar.JarOutputStream;
82
import java.util.jar.Manifest;
83
import java.util.logging.Logger;
84
 
85
import javax.security.auth.x500.X500Principal;
86
import java.security.cert.X509Certificate;
87
 
88
/**
89
 * A helper class for the .SF file found in signed jars.
90
 */
91
public class SFHelper
92
{
93
  private static final Logger log = Logger.getLogger(SFHelper.class.getName());
94
  private static final int READY = 0;
95
  private static final int STARTED = 1;
96
  private static final int FINISHED = 2;
97
  private static final int SF_GENERATED = 3;
98
  private static final int DSA_GENERATED = 4;
99
  /** http://asn1.elibel.tm.fr/cgi-bin/oid/display?oid=1.3.14.3.2.26&action=display */
100
  private static final OID hashAlgorithmIdentifierSHA1 = new OID("1.3.14.3.2.26"); //$NON-NLS-1$
101
 
102
  private int state;
103
  private JarFile jar;
104
  private Manifest manifest;
105
  private Attributes sfMainAttributes;
106
  private Map<String, Attributes> sfEntries;
107
  private byte[] sfBytes;
108
  private HashUtils util;
109
 
110
  /**
111
   * @param jar the JAR archive the .SF file belongs to.
112
   */
113
  public SFHelper(JarFile jar)
114
  {
115
    super();
116
 
117
    this.jar = jar;
118
    this.state = READY;
119
  }
120
 
121
  /**
122
   * Writes the contents of the <code>.SF</code> file to the designated JAR
123
   * output stream. Line-endings are platform-independent and consist of the
124
   * 2-codepoint sequence <code>0x0D</code> and <code>0x0A</code>.
125
   *
126
   * @param jar the JAR output stream to write a <code>.SF</code> file to.
127
   * @throws IOException if an I/O related exception occurs during the process.
128
   */
129
  void writeSF(JarOutputStream jar) throws IOException
130
  {
131
    if (this.state != FINISHED)
132
      throw new IllegalStateException(Messages.getString("SFHelper.1")); //$NON-NLS-1$
133
 
134
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
135
    JarUtils.writeSFManifest(sfMainAttributes, sfEntries, baos);
136
    sfBytes = baos.toByteArray();
137
    if (Configuration.DEBUG)
138
      log.fine("\n" + Util.dumpString(sfBytes, "+++ sfBytes ")); //$NON-NLS-1$ //$NON-NLS-2$
139
    jar.write(sfBytes);
140
    jar.flush();
141
 
142
    this.state = SF_GENERATED;
143
  }
144
 
145
  /**
146
   * The contents of the .DSA file is the DER encoded form of a PKCS#7
147
   * ContentInfo of the type SignedData.
148
   * <p>
149
   * The ContentInfo ASN.1 syntax is as described in the "PKCS#7 Cryptographic
150
   * Message Syntax Standard" (RSA Labs) specifications:
151
   * <pre>
152
   * ContentInfo ::= SEQUENCE {
153
   *   contentType     ContentType,
154
   *   content     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
155
   * }
156
   *
157
   * ContentType ::= OBJECT IDENTIFIER
158
   * </pre>
159
   * <p>
160
   * The ContentType is an OID which determines the type of the contents field
161
   * that follows it. For the .DSA file the OID is "1.2.840.113549.1.7.2", while
162
   * the content field is the byte array representing the DER encoded form of a
163
   * SignedData content-type. The ASN.1 syntax of the SignedData type is as
164
   * follows:
165
   * <pre>
166
   * SignedData ::= SEQUENCE {
167
   *   version          Version, -- always 1 for PKCS#7 1.5
168
   *   digestAlgorithms DigestAlgorithmIdentifiers,
169
   *   contentInfo      ContentInfo,
170
   *   certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
171
   *   crls         [1] IMPLICIT CertificateRevocationLists OPTIONAL,
172
   *   signerInfos      SignerInfos
173
   * }
174
   *
175
   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
176
   *
177
   * SignerInfos ::= SET OF SignerInfo
178
   * </pre>
179
   * <p>
180
   * Finally the SignerInfo is a per-signer structure. Its ASN.1 syntax looks
181
   * like so:
182
   * <pre>
183
   * SignerInfo ::= SEQUENCE {
184
   *   version                       Version, -- always 1 for PKCS#7 1.5
185
   *   issuerAndSerialNumber         IssuerAndSerialNumber,
186
   *   digestAlgorithm               DigestAlgorithmIdentifier,
187
   *   authenticatedAttributes   [0] IMPLICIT Attributes OPTIONAL,
188
   *   digestEncryptionAlgorithm     DigestEncryptionAlgorithmIdentifier,
189
   *   encryptedDigest               EncryptedDigest,
190
   *   unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
191
   * }
192
   *
193
   * EncryptedDigest ::= OCTET STRING
194
   * </pre>
195
   *
196
   * @param jar the JAR output stream to write a <code>.DSA</code> file to.
197
   * @param signerKey the private key to sign with.
198
   * @param certificates the possibly null signer certificate chain.
199
   * @param internalSF if <code>true</code> then include the .SF file contents
200
   * in the signed .DSA file; otherwise don't.
201
   * @throws IOException if an I/O related exception occurs during the process.
202
   * @throws CRLException
203
   * @throws CertificateEncodingException
204
   */
205
  void writeDSA(JarOutputStream jar, PrivateKey signerKey,
206
                Certificate[] certificates, boolean internalSF)
207
      throws IOException, CertificateEncodingException, CRLException
208
  {
209
    if (this.state != SF_GENERATED)
210
      throw new IllegalStateException(Messages.getString("SFHelper.4")); //$NON-NLS-1$
211
 
212
    if (Configuration.DEBUG)
213
      log.fine("+++ signer private key = " + signerKey); //$NON-NLS-1$
214
    ISignature signatureAlgorithm;
215
    ISignatureCodec signatureCodec;
216
    OID digestEncryptionAlgorithmOID;
217
    if (signerKey instanceof DSAPrivateKey)
218
      {
219
        signatureAlgorithm = new DSSSignature();
220
        signatureCodec = new DSSSignatureX509Codec();
221
        digestEncryptionAlgorithmOID = Main.DSA_SIGNATURE_OID;
222
      }
223
    else if (signerKey instanceof RSAPrivateKey)
224
      {
225
        signatureAlgorithm = new RSAPKCS1V1_5Signature(Registry.MD5_HASH);
226
        signatureCodec = new RSAPKCS1V1_5SignatureX509Codec();
227
        digestEncryptionAlgorithmOID = Main.RSA_SIGNATURE_OID;
228
      }
229
    else
230
      throw new SecurityException(Messages.getString("SFHelper.6")); //$NON-NLS-1$
231
 
232
    Map signatureAttributes = new HashMap();
233
    signatureAttributes.put(ISignature.SIGNER_KEY, signerKey);
234
    signatureAlgorithm.setupSign(signatureAttributes);
235
    signatureAlgorithm.update(sfBytes, 0, sfBytes.length);
236
    Object signature = signatureAlgorithm.sign();
237
    byte[] signedSFBytes = signatureCodec.encodeSignature(signature);
238
    if (Configuration.DEBUG)
239
      log.fine("\n" + Util.dumpString(signedSFBytes, "+++ signedSFBytes ")); //$NON-NLS-1$ //$NON-NLS-2$
240
 
241
    Set<DERValue> digestAlgorithms = new HashSet<DERValue>();
242
    List<DERValue> digestAlgorithm = new ArrayList<DERValue>(2);
243
    DERValue derDigestAlgorithmOID = new DERValue(DER.OBJECT_IDENTIFIER,
244
                                                  hashAlgorithmIdentifierSHA1);
245
    DERValue derDigestAlgorithmParams = new DERValue(DER.NULL, null);
246
    digestAlgorithm.add(derDigestAlgorithmOID);
247
    digestAlgorithm.add(derDigestAlgorithmParams);
248
    DERValue derDigestAlgorithm = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
249
                                               digestAlgorithm);
250
    digestAlgorithms.add(derDigestAlgorithm);
251
 
252
    // TODO (rsn): test with internalsf == true
253
    PKCS7Data data = internalSF ? new PKCS7Data(sfBytes) : null;
254
 
255
    X509CRL[] crls = null;
256
 
257
    Set<SignerInfo> signerInfos = new HashSet<SignerInfo>();
258
    X509Certificate cert = (X509Certificate) certificates[0];
259
    try
260
      {
261
        cert.checkValidity();
262
      }
263
    catch (CertificateExpiredException x)
264
      {
265
        String issuerName = getIssuerName(cert);
266
        String subjectName = getSubjectName(cert);
267
        Date notAfterDate = getNotAfterDate(cert);
268
        System.out.println(Messages.getFormattedString("SFHelper.0", //$NON-NLS-1$
269
                                                       new Object[] { issuerName,
270
                                                                      subjectName,
271
                                                                      notAfterDate }));
272
      }
273
    catch (CertificateNotYetValidException x)
274
      {
275
        String issuerName = getIssuerName(cert);
276
        String subjectName = getSubjectName(cert);
277
        Date notBeforeDate = getNotBeforeDate(cert);
278
        System.out.println(Messages.getFormattedString("SFHelper.11", //$NON-NLS-1$
279
                                                       new Object[] { issuerName,
280
                                                                      subjectName,
281
                                                                      notBeforeDate }));
282
      }
283
    X500Principal issuer = cert.getIssuerX500Principal();
284
    BigInteger serialNumber = cert.getSerialNumber();
285
    byte[] authenticatedAttributes = null;
286
    byte[] encryptedDigest = signedSFBytes;
287
    byte[] unauthenticatedAttributes = null;
288
    SignerInfo signerInfo = new SignerInfo(issuer,
289
                                           serialNumber,
290
                                           hashAlgorithmIdentifierSHA1,
291
                                           authenticatedAttributes,
292
                                           digestEncryptionAlgorithmOID,
293
                                           encryptedDigest,
294
                                           unauthenticatedAttributes);
295
    signerInfos.add(signerInfo);
296
 
297
    PKCS7SignedData dsaContents = new PKCS7SignedData(digestAlgorithms,
298
                                                      data,
299
                                                      certificates,
300
                                                      crls,
301
                                                      signerInfos);
302
    dsaContents.encode(jar);
303
 
304
    jar.flush();
305
    this.state = DSA_GENERATED;
306
  }
307
 
308
  Manifest getManifest()
309
  {
310
    return this.manifest;
311
  }
312
 
313
  void startSigning() throws IOException
314
  {
315
    if (this.state != READY)
316
      throw new IllegalStateException(Messages.getString("SFHelper.9")); //$NON-NLS-1$
317
 
318
    Manifest oldManifest = jar.getManifest();
319
    this.manifest = oldManifest == null ? new Manifest()
320
                                        : new Manifest(oldManifest);
321
    this.sfMainAttributes = new Attributes();
322
    this.sfEntries = new HashMap<String, Attributes>();
323
    util = new HashUtils();
324
 
325
    this.state = STARTED;
326
  }
327
 
328
  /**
329
   * Hashes the designated JAR entry (the file itself); adds the resulting hash
330
   * as an attribute to the manifest, and computes the hash of the added (to
331
   * the Manifest) two headers and add the result as an attribute of the
332
   * corresponding entry in the .SF file.
333
   */
334
  void updateEntry(JarEntry entry) throws IOException
335
  {
336
    if (this.state != STARTED)
337
      throw new IllegalStateException(Messages.getString("SFHelper.10")); //$NON-NLS-1$
338
 
339
    String name = entry.getName();
340
    InputStream jeis = jar.getInputStream(entry);
341
    String hash = util.hashStream(jeis);
342
    if (Configuration.DEBUG)
343
      log.fine("Hash of " + name + " = " + hash); //$NON-NLS-1$ //$NON-NLS-2$
344
 
345
    Attributes mainfestAttributes = manifest.getAttributes(name);
346
    if (mainfestAttributes == null)
347
      {
348
        mainfestAttributes = new Attributes();
349
        manifest.getEntries().put(name, mainfestAttributes);
350
      }
351
 
352
    mainfestAttributes.putValue(Main.DIGEST, hash);
353
 
354
    // hash the newly added 2-header block and add it as an attribute to .SF
355
 
356
    String sfHash = util.hashManifestEntry(name, hash);
357
    Attributes sfAttributes = sfEntries.get(name);
358
    if (sfAttributes == null)
359
      {
360
        sfAttributes = new Attributes();
361
        sfEntries.put(name, sfAttributes);
362
      }
363
 
364
    sfAttributes.putValue(Main.DIGEST, sfHash);
365
    if (Configuration.DEBUG)
366
      {
367
        log.fine("Name: " + name); //$NON-NLS-1$
368
        log.fine(Main.DIGEST + ": " + sfHash); //$NON-NLS-1$
369
        log.fine(""); //$NON-NLS-1$
370
      }
371
  }
372
 
373
  /**
374
   * @param sectionsOnly whether to compute, in addition to the files, the hash
375
   * of the mainfest itself (<code>false</code>) or not (<code>true</code>).
376
   */
377
  void finishSigning(boolean sectionsOnly) throws IOException
378
  {
379
    if (state != STARTED)
380
      throw new IllegalStateException(Messages.getString("SFHelper.10")); //$NON-NLS-1$
381
 
382
    if (sectionsOnly)
383
      return;
384
 
385
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
386
    manifest.write(baos);
387
    baos.flush();
388
    String manifestHash = util.hashByteArray(baos.toByteArray());
389
    if (Configuration.DEBUG)
390
      log.fine("Hashed Manifest " + manifestHash); //$NON-NLS-1$
391
    sfMainAttributes.putValue(Main.DIGEST_MANIFEST, manifestHash);
392
 
393
    this.state = FINISHED;
394
  }
395
 
396
  /**
397
   * Given an X.509 certificate this method returns the string representation of
398
   * the Issuer Distinguished Name.
399
   *
400
   * @param cert an X.509 certificate.
401
   * @return the string representation of the Issuer's DN.
402
   */
403
  private String getIssuerName(X509Certificate cert)
404
  {
405
    X500Principal xp = cert.getIssuerX500Principal();
406
    if (xp == null)
407
      {
408
        if (Configuration.DEBUG)
409
          log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
410
                   + ", has null Issuer. Return [unknown]"); //$NON-NLS-1$
411
        return Messages.getString("SFHelper.14"); //$NON-NLS-1$
412
      }
413
    String result = xp.getName();
414
    if (result == null)
415
      {
416
        if (Configuration.DEBUG)
417
          log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
418
                   + ", has an Issuer with null DN. Return [unnamed]"); //$NON-NLS-1$
419
        return Messages.getString("SFHelper.17"); //$NON-NLS-1$
420
      }
421
    return result;
422
  }
423
 
424
  /**
425
   * Given an X.509 certificate this method returns the string representation of
426
   * the Subject Distinguished Name.
427
   *
428
   * @param cert an X.509 certificate.
429
   * @return the string representation of the Subject's DN.
430
   */
431
  private String getSubjectName(X509Certificate cert)
432
  {
433
    X500Principal xp = cert.getSubjectX500Principal();
434
    if (xp == null)
435
      {
436
        if (Configuration.DEBUG)
437
          log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
438
                   + ", has null Subject. Return [unknown]"); //$NON-NLS-1$
439
        return Messages.getString("SFHelper.14"); //$NON-NLS-1$
440
      }
441
    String result = xp.getName();
442
    if (result == null)
443
      {
444
        if (Configuration.DEBUG)
445
          log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
446
                   + ", has a Subject with null DN. Return [unnamed]"); //$NON-NLS-1$
447
        return Messages.getString("SFHelper.17"); //$NON-NLS-1$
448
      }
449
    return result;
450
  }
451
 
452
  /**
453
   * Given an X.509 certificate this method returns the end validity date of
454
   * this certificate.
455
   *
456
   * @param cert an X.509 certificate.
457
   * @return the date when this certificate stops being valid.
458
   */
459
  private Date getNotAfterDate(X509Certificate cert)
460
  {
461
    Date result = cert.getNotAfter();
462
    if (result == null)
463
      {
464
        if (Configuration.DEBUG)
465
          log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
466
                   + ", has null start-validity date. Return epoch"); //$NON-NLS-1$
467
        return new Date(0);
468
      }
469
    return result;
470
  }
471
 
472
  /**
473
   * Given an X.509 certificate this method returns the start validity date of
474
   * this certificate.
475
   *
476
   * @param cert an X.509 certificate.
477
   * @return the date when this certificate starts being valid.
478
   */
479
  private Date getNotBeforeDate(X509Certificate cert)
480
  {
481
    Date result = cert.getNotBefore();
482
    if (result == null)
483
      {
484
        if (Configuration.DEBUG)
485
          log.fine("Certiticate, with serial number " + cert.getSerialNumber() //$NON-NLS-1$
486
                   + ", has null end-validity date. Return epoch"); //$NON-NLS-1$
487
        return new Date(0);
488
      }
489
    return result;
490
  }
491
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.