Class GenericCertificate

  • All Implemented Interfaces:
    java.io.Serializable

    public final class GenericCertificate
    extends java.lang.Object
    implements java.io.Serializable
    This non-visual JavaBean implements authenticated runtime objects whose integrity cannot be compromised without being detected. The idea and the design of this class is inspired by both SignedObject and Certificate.

    More specifically, a GenericCertificate contains an XML string encoded representation of an arbitrary object in the "encoded" property and a Base64 immutable string representation of the object's corresponding digital signature in the "signature" property. The selection of this representation form and the design of this class as a plain JavaBean allows its instances to be serialized using either this package's PersistenceService, JDK's XMLEncoder, or the vanilla ObjectOutputStream.

    For an object to be successfully digitally signed, it must support serialisation via JDK's XMLEncoder, for which this package provides the class PersistenceService. This easy-to-use class allows you to provide custom PersistenceDelegate instances for the serialisation of any classes which do not implement the JavaBean design pattern and are not supported by XMLEncoder as a default.

    Whenever an instance of this GenericCertificate class is created, you can arbitrarily set and get its "encoded" and "signature" properties, allowing you to provide even custom deserialisation methods other than this class already provides via the aforementioned classes. However, once this instance is used to either sign or verify another object it gets locked, allowing subsequent read access to its properties only.

    The underlying signing algorithm is designated by the Signature object passed to the sign and the verify methods.

    A typical usage for signing is the following: <pre> GenericCertificate cert = new GenericCertificate(); Signature signingEngine = Signature.getInstance(algorithm, provider); try { cert.sign(myObject, signingKey, signingEngine); } catch (PropertyVetoException signingVetoed) { // ... } catch (PersistenceServiceException serialisationFailed) { // ... } catch (InvalidKeyException invalidKey) { // ... } catch (SignatureException signingEngineBroken) { // ... } </pre> A typical usage for verification is the following (having received GenericCertificate cert): <pre> Signature verificationEngine = Signature.getInstance(algorithm, provider); try { cert.verify(publicKey, verificationEngine)); } catch (PropertyVetoException verificationVetoed) { // ... } catch (InvalidKeyException invalidKey) { // ... } catch (SignatureException verificationEngineBroken) { // ... } catch (GenericCertificateException integrityCompromised) { // ... } Object myObject = cert.getContent(); </pre> Several points are worth noting:

    • There is no need to initialize the signing or verification engine, as it will be re-initialized inside the sign(java.lang.Object, java.security.PrivateKey, java.security.Signature) and verify(java.security.PublicKey, java.security.Signature) methods. Secondly, for verification to succeed, the specified public key must be the public key corresponding to the private key used to sign the GenericCertificate.
    • In contrast to SignedObject, this class adds more security as it is impossible to retrieve the signed object without verifying the signature before. A SignedObject however could be deserialised from a compromised file and the application developer may erraticaly forget to call the SignedObject.verify(java.security.PublicKey, java.security.Signature) method before retrieving the signed object by calling SignedObject.getObject().
    • More importantly, for flexibility reasons, the sign() and verify() methods allow for customized signature engines, which can implement signature algorithms that are not installed formally as part of a crypto provider. However, it is crucial that the programmer writing the verifier code be aware what Signature engine is being used, as its own implementation of the Signature.verify(byte[]) method is invoked to verify a signature. In other words, a malicious Signature engine may choose to always return true on verification in an attempt to bypass a security check.
    • The signature algorithm can be, among others, the NIST standard DSA, using DSA and SHA-1. The algorithm is specified using the same convention as that for signatures. The DSA algorithm using the SHA-1 message digest algorithm can be specified, for example, as "SHA/DSA" or "SHA-1/DSA" (they are equivalent). In the case of RSA, there are multiple choices for the message digest algorithm, so the signing algorithm could be specified as, for example, "MD2/RSA", "MD5/RSA" or "SHA-1/RSA". The algorithm name must be specified, as there is no default.
    • The name of the Cryptography Package Provider is designated by the Signature parameter to the sign() and verify() methods. If the provider is not specified, the default provider is used. Each installation can be configured to use a particular provider as default.
    • The property change listeners are not persistet when using ObjectOutputStream or XMLEncoder.
    • Object.equals(Object) and Object.hashCode() are not overridden by this class because different JVMs will produce different literal encodings of the same object and we cannot rely on a proper equals(...) implementation in the class of a signed object.
    Potential applications of GenericCertificate include:
    • It can be used internally to any Java runtime as an unforgeable authorization token -- one that can be passed around without the fear that the token can be maliciously modified without being detected.
    • It can be used to sign and serialize data/object for storage outside the Java runtime (e.g., storing critical access control data on disk).
    • Nested GenericCertificates can be used to construct a logical sequence of signatures, resembling a chain of authorization and delegation.

    This class is thread-safe.

    Author:
    Christian Schlichtherle
    See Also:
    Signature, SignedObject, Certificate, Serialized Form
    • Field Summary

      Fields 
      Modifier and Type Field Description
      static int DEFAULT_BUFSIZE
      10KB - the default buffer size for buffered I/O.
      static java.lang.String XML_CHARSET
      "UTF-8" - the character encoding used by XMLEncoder and XMLDecoder.
    • Method Summary

      All Methods Instance Methods Concrete Methods Deprecated Methods 
      Modifier and Type Method Description
      void addPropertyChangeListener​(java.beans.PropertyChangeListener l)
      Adds a PropertyChangeListener to the listener list.
      void addVetoableChangeListener​(java.beans.VetoableChangeListener l)
      Adds a VetoableChangeListener to the listener list.
      protected void firePropertyChange​(java.beans.PropertyChangeEvent evt)  
      protected void fireVetoableChange​(java.beans.PropertyChangeEvent evt)  
      java.lang.Object getContent()
      Returns a clone of the certificate's content as it was signed or verified before.
      java.lang.String getEncoded()
      Getter for the property encoded.
      java.lang.String getSignature()
      Getter for the property signature.
      java.lang.String getSignatureAlgorithm()
      Getter for the property signatureAlgorithm.
      java.lang.String getSignatureEncoding()
      Getter for the property signatureEncoding.
      boolean isLocked()
      Returns the "locked" property of this generic certificate.
      void removePropertyChangeListener​(java.beans.PropertyChangeListener l)
      Removes a PropertyChangeListener from the listener list.
      void removeVetoableChangeListener​(java.beans.VetoableChangeListener l)
      Removes a VetoableChangeListener from the listener list.
      void setEncoded​(java.lang.String encoded)
      Setter for the bound property encoded.
      void setSignature​(java.lang.String signature)
      Setter for the bound property signature.
      void setSignatureAlgorithm​(java.lang.String signatureAlgorithm)
      Setter for the bound property signatureAlgorithm.
      void setSignatureEncoding​(java.lang.String signatureEncoding)
      void sign​(java.lang.Object content, java.security.PrivateKey signingKey, java.security.Signature signingEngine)
      Encodes and signs the given content in this certificate and locks it.
      void verify​(java.security.PublicKey verificationKey, java.security.Signature verificationEngine)
      Verifies the digital signature of the encoded content in this certificate and locks it.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • XML_CHARSET

        public static final java.lang.String XML_CHARSET
        "UTF-8" - the character encoding used by XMLEncoder and XMLDecoder.
        See Also:
        Constant Field Values
      • DEFAULT_BUFSIZE

        public static final int DEFAULT_BUFSIZE
        10KB - the default buffer size for buffered I/O.
        See Also:
        Constant Field Values
    • Constructor Detail

      • GenericCertificate

        public GenericCertificate()
        Creates a new generic certificate.
      • GenericCertificate

        public GenericCertificate​(GenericCertificate cert)
        Copy constructor for the given generic certificate. Note that the new certificate is unlocked and does not have any event listeners.
    • Method Detail

      • sign

        public final void sign​(java.lang.Object content,
                               java.security.PrivateKey signingKey,
                               java.security.Signature signingEngine)
                        throws java.lang.NullPointerException,
                               GenericCertificateIsLockedException,
                               java.beans.PropertyVetoException,
                               PersistenceServiceException,
                               java.security.InvalidKeyException
        Encodes and signs the given content in this certificate and locks it.

        Please note the following:

        • This method will throw a PropertyVetoException if this certificate is already locked, i.e. if it has been signed or verified before.
        • Because this method locks this certificate, a subsequent call to sign(Object, PrivateKey, Signature) or verify(PublicKey, Signature) is redundant and will throw a PropertyVetoException. Use isLocked() to detect whether a generic certificate has been successfuly signed or verified before or call getContent() and expect an Exception to be thrown if it hasn't.
        • There is no way to unlock this certificate. Call the copy constructor of GenericCertificate if you need an unlocked copy of the certificate.
        Parameters:
        content - The object to sign. This must either be a JavaBean or an instance of any other class which is supported by {@link PersistenceService} - maybe null.
        signingKey - The private key for signing - may not be null.
        signingEngine - The signature signing engine - may not be null.
        Throws:
        java.lang.NullPointerException - If the preconditions for the parameters do not hold.
        GenericCertificateIsLockedException - If this certificate is already locked by signing or verifying it before. Note that this is actually a subclass of PropertyVetoException.
        java.beans.PropertyVetoException - If locking the certifificate (and thus signing the object) is vetoed by any listener.
        PersistenceServiceException - If the object cannot be serialised.
        java.security.InvalidKeyException - If the verification key is invalid.
      • verify

        public final void verify​(java.security.PublicKey verificationKey,
                                 java.security.Signature verificationEngine)
                          throws java.lang.NullPointerException,
                                 GenericCertificateIsLockedException,
                                 java.beans.PropertyVetoException,
                                 java.security.InvalidKeyException,
                                 java.security.SignatureException,
                                 GenericCertificateIntegrityException
        Verifies the digital signature of the encoded content in this certificate and locks it.

        Please note the following:

        • This method will throw a PropertyVetoException if this certificate is already locked, i.e. if it has been signed or verified before.
        • Because this method locks this certificate, a subsequent call to sign(Object, PrivateKey, Signature) or verify(PublicKey, Signature) is redundant and will throw a PropertyVetoException. Use isLocked() to detect whether a generic certificate has been successfuly signed or verified before or call getContent() and expect an Exception to be thrown if it hasn't.
        • There is no way to unlock this certificate. Call the copy constructor of GenericCertificate if you need an unlocked copy of the certificate.
        Parameters:
        verificationKey - The public key for verification - may not be null.
        verificationEngine - The signature verification engine - may not be null.
        Throws:
        java.lang.NullPointerException - If the preconditions for the parameters do not hold.
        GenericCertificateIsLockedException - If this certificate is already locked by signing or verifying it before. Note that this is actually a subclass of PropertyVetoException.
        java.beans.PropertyVetoException - If locking the certifificate (and thus verifying the object) is vetoed by any listener.
        java.security.InvalidKeyException - If the verification key is invalid.
        java.security.SignatureException - If signature verification failed.
        GenericCertificateIntegrityException - If the integrity of this certificate has been compromised.
      • isLocked

        public final boolean isLocked()
        Returns the "locked" property of this generic certificate. If true, an object was successfully signed or verified before and a clone can be safely retrieved using getContent().
      • getContent

        public java.lang.Object getContent()
                                    throws GenericCertificateNotLockedException,
                                           PersistenceServiceException
        Returns a clone of the certificate's content as it was signed or verified before. You should save the returned object for later use as each call to this method is pretty expensive in terms of runtime and memory. This method may return null if this has been signed before.
        Throws:
        GenericCertificateNotLockedException - If no content has been signed or verified before. Note that this is ultimately a RuntimeException.
        PersistenceServiceException - If the signed object cannot get reinstantiated from its XML representation for some reason. This may happen for example if the signed object was created by a more recent version of its class which contains additional properties which are not supported by earlier versions.
      • getEncoded

        public final java.lang.String getEncoded()
        Getter for the property encoded. The default is null.
        Returns:
        Value of property encoded.
      • setEncoded

        public void setEncoded​(java.lang.String encoded)
                        throws GenericCertificateIsLockedException
        Setter for the bound property encoded.
        Parameters:
        encoded - The new encoded representation of the signed object - may be null.
        Throws:
        GenericCertificateIsLockedException - If this certificate is already locked by signing or verifying it before. Note that this is actually a subclass of PropertyVetoException.
      • getSignature

        public final java.lang.String getSignature()
        Getter for the property signature. The default is null.
        Returns:
        Value of property signature.
      • setSignature

        public void setSignature​(java.lang.String signature)
                          throws GenericCertificateIsLockedException
        Setter for the bound property signature.
        Parameters:
        signature - The signature encoded as a string - may be null.
        Throws:
        GenericCertificateIsLockedException - If this certificate is already locked by signing or verifying it before. Note that this is actually a subclass of PropertyVetoException.
      • getSignatureAlgorithm

        public final java.lang.String getSignatureAlgorithm()
        Getter for the property signatureAlgorithm. The default is null.
        Returns:
        The signature algorithm.
      • setSignatureAlgorithm

        public void setSignatureAlgorithm​(java.lang.String signatureAlgorithm)
                                   throws GenericCertificateIsLockedException
        Setter for the bound property signatureAlgorithm.
        Parameters:
        signatureAlgorithm - The string identifying the signature algorithm - may be null.
        Throws:
        GenericCertificateIsLockedException - If this certificate is already locked by signing or verifying it before. Note that this is actually a subclass of PropertyVetoException.
      • getSignatureEncoding

        public final java.lang.String getSignatureEncoding()
        Getter for the property signatureEncoding. The default is null.
        Returns:
        The character encoding of the signature string.
      • setSignatureEncoding

        public void setSignatureEncoding​(java.lang.String signatureEncoding)
                                  throws GenericCertificateIsLockedException
        Deprecated.
        Currently ignored by verify(java.security.PublicKey, java.security.Signature). Only provided to cause XMLEncoder to encode this property for upwards compatibility.
        Setter for the bound property signatureEncoding.
        Parameters:
        signatureEncoding - The string identifying the signature encoding - may be null.
        Throws:
        GenericCertificateIsLockedException - If this certificate is already locked by signing or verifying it before. Note that this is actually a subclass of PropertyVetoException.
      • addVetoableChangeListener

        public final void addVetoableChangeListener​(java.beans.VetoableChangeListener l)
        Adds a VetoableChangeListener to the listener list.
        Parameters:
        l - The listener to add.
      • removeVetoableChangeListener

        public final void removeVetoableChangeListener​(java.beans.VetoableChangeListener l)
        Removes a VetoableChangeListener from the listener list.
        Parameters:
        l - The listener to remove.
      • fireVetoableChange

        protected final void fireVetoableChange​(java.beans.PropertyChangeEvent evt)
                                         throws java.beans.PropertyVetoException
        Throws:
        java.beans.PropertyVetoException
      • addPropertyChangeListener

        public final void addPropertyChangeListener​(java.beans.PropertyChangeListener l)
        Adds a PropertyChangeListener to the listener list.
        Parameters:
        l - The listener to add.
      • removePropertyChangeListener

        public final void removePropertyChangeListener​(java.beans.PropertyChangeListener l)
        Removes a PropertyChangeListener from the listener list.
        Parameters:
        l - The listener to remove.
      • firePropertyChange

        protected final void firePropertyChange​(java.beans.PropertyChangeEvent evt)