Merge remote-tracking branch 'origin/signature-implementation'
						commit
						2ca706492a
					
				| 
						 | 
					@ -1,6 +1,10 @@
 | 
				
			||||||
.gradle
 | 
					.gradle
 | 
				
			||||||
.idea
 | 
					.idea
 | 
				
			||||||
build
 | 
					build
 | 
				
			||||||
 | 
					bin
 | 
				
			||||||
 | 
					.settings
 | 
				
			||||||
 | 
					.classpath
 | 
				
			||||||
 | 
					.project
 | 
				
			||||||
out
 | 
					out
 | 
				
			||||||
*.iml
 | 
					*.iml
 | 
				
			||||||
*.ipr
 | 
					*.ipr
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,15 @@ dependencies {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*==== You probably don't have to edit below this line =======*/
 | 
					/*==== You probably don't have to edit below this line =======*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The run task added by the application plugin
 | 
				
			||||||
 | 
					// is also of type JavaExec.
 | 
				
			||||||
 | 
					tasks.withType(JavaExec) {
 | 
				
			||||||
 | 
					    // Assign all Java system properties from
 | 
				
			||||||
 | 
					    // the command line to the JavaExec task.
 | 
				
			||||||
 | 
					    systemProperties System.properties
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protobuf {
 | 
					protobuf {
 | 
				
			||||||
    // Configure the protoc executable
 | 
					    // Configure the protoc executable
 | 
				
			||||||
    protoc {
 | 
					    protoc {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,10 @@ dependencies {
 | 
				
			||||||
    // Google protobufs
 | 
					    // Google protobufs
 | 
				
			||||||
    compile 'com.google.protobuf:protobuf-java:3.+'
 | 
					    compile 'com.google.protobuf:protobuf-java:3.+'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Crypto
 | 
				
			||||||
 | 
					    compile 'org.bouncycastle:bcprov-jdk15on:1.53'
 | 
				
			||||||
 | 
					    compile 'org.bouncycastle:bcpkix-jdk15on:1.53'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    testCompile 'junit:junit:4.+'
 | 
					    testCompile 'junit:junit:4.+'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    runtime 'org.codehaus.groovy:groovy:2.4.+'
 | 
					    runtime 'org.codehaus.groovy:groovy:2.4.+'
 | 
				
			||||||
| 
						 | 
					@ -53,6 +57,16 @@ dependencies {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*==== You probably don't have to edit below this line =======*/
 | 
					/*==== You probably don't have to edit below this line =======*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The run task added by the application plugin
 | 
				
			||||||
 | 
					// is also of type JavaExec.
 | 
				
			||||||
 | 
					tasks.withType(JavaExec) {
 | 
				
			||||||
 | 
					    // Assign all Java system properties from
 | 
				
			||||||
 | 
					    // the command line to the JavaExec task.
 | 
				
			||||||
 | 
					    systemProperties System.properties
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protobuf {
 | 
					protobuf {
 | 
				
			||||||
    // Configure the protoc executable
 | 
					    // Configure the protoc executable
 | 
				
			||||||
    protoc {
 | 
					    protoc {
 | 
				
			||||||
| 
						 | 
					@ -87,33 +101,6 @@ idea {
 | 
				
			||||||
 *        "Fat" Build targets
 | 
					 *        "Fat" Build targets
 | 
				
			||||||
 *===================================*/
 | 
					 *===================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
task fatjar(type: Jar) {
 | 
					 | 
				
			||||||
    description = "Generate a single jar containing everything. Use -Pfatmain=... to override main class"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    destinationDir = buildDir
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
 | 
					 | 
				
			||||||
    def testJar = hasProperty('test')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    appendix = "${fatMain}-fat"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (testJar) {
 | 
					 | 
				
			||||||
        from sourceSets.test.output
 | 
					 | 
				
			||||||
        from configurations.testRuntime.collect { it.isDirectory() ? it : zipTree(it) }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    from sourceSets.main.output // that's it
 | 
					 | 
				
			||||||
    from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    exclude 'META-INF/MANIFEST.MF'
 | 
					 | 
				
			||||||
    exclude 'META-INF/*.SF'
 | 
					 | 
				
			||||||
    exclude 'META-INF/*.DSA'
 | 
					 | 
				
			||||||
    exclude 'META-INF/*.RSA'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    manifest { attributes 'Main-Class': fatMain }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
task mavenCapsule(type: MavenCapsule){
 | 
					task mavenCapsule(type: MavenCapsule){
 | 
				
			||||||
    description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
 | 
					    description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,13 +8,6 @@ import java.security.MessageDigest;
 | 
				
			||||||
 * Created by talm on 11/9/15.
 | 
					 * Created by talm on 11/9/15.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public interface Digest {
 | 
					public interface Digest {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Marker between messages
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static final byte[] CONCAT_MARKER = {(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
 | 
					 | 
				
			||||||
            (byte) 0xba, (byte) 0x1d, (byte) 0xfa, (byte) 0xce};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Completes the hash computation by performing final operations such as padding.
 | 
					     * Completes the hash computation by performing final operations such as padding.
 | 
				
			||||||
     * (copied from {@link MessageDigest#digest()})
 | 
					     * (copied from {@link MessageDigest#digest()})
 | 
				
			||||||
| 
						 | 
					@ -25,9 +18,7 @@ public interface Digest {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Updates the digest using the specified message (in serialized wire form)
 | 
					     * Updates the digest using the specified message (in serialized wire form)
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * Includes a special message concatenation marker (the 64 bit message {@link #CONCAT_MARKER}) in the digest (digesting a single message
 | 
					     * Each message is (automatically) prepended with its length as a 32-bit big-endian unsigned integer.
 | 
				
			||||||
     * will give a different result than the same message split into two messages).
 | 
					 | 
				
			||||||
     * Messages must not contain the {@link #CONCAT_MARKER}) marker.
 | 
					 | 
				
			||||||
     * @param msg
 | 
					     * @param msg
 | 
				
			||||||
     * @return
 | 
					     * @return
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,16 +2,92 @@ package meerkat.crypto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.protobuf.Message;
 | 
					import com.google.protobuf.Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.security.auth.callback.CallbackHandler;
 | 
				
			||||||
 | 
					import javax.security.auth.callback.PasswordCallback;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.security.InvalidKeyException;
 | 
				
			||||||
 | 
					import java.security.KeyStore;
 | 
				
			||||||
 | 
					import java.security.SignatureException;
 | 
				
			||||||
 | 
					import java.security.UnrecoverableKeyException;
 | 
				
			||||||
 | 
					import java.security.cert.CertificateException;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import static meerkat.protobuf.Crypto.*;
 | 
					import static meerkat.protobuf.Crypto.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by talm on 25/10/15.
 | 
					 * Created by talm on 25/10/15.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Sign arrays of messages
 | 
					 * Sign and verifyarrays of messages
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public interface DigitalSignature { // Extends SCAPI DigitalSignature
 | 
					public interface DigitalSignature {
 | 
				
			||||||
    public Signature sign(List<Message> msg);
 | 
					    final public static String CERTIFICATE_ENCODING_X509 = "X.509";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Load a set of certificates from an input stream.
 | 
				
			||||||
 | 
					     * This will consume the entire stream.
 | 
				
			||||||
 | 
					     * Certificates can be either DER-encoded (binary) or PEM (base64) encoded.
 | 
				
			||||||
 | 
					     * This may be called multiple times to load several different certificates.
 | 
				
			||||||
 | 
					     * It must be called before calling {@link #verify()}.
 | 
				
			||||||
 | 
					     * @param certStream source from which certificates are loaded
 | 
				
			||||||
 | 
					     * @throws CertificateException on parsing errors
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void loadVerificationCertificates(InputStream certStream)
 | 
				
			||||||
 | 
					            throws CertificateException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Clear the loaded verification certificates.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void clearVerificationCertificates();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add msg to the content stream to be verified / signed. Each message is (automatically)
 | 
				
			||||||
 | 
					     * prepended with its length as a 32-bit big-endian unsigned integer.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param msg
 | 
				
			||||||
 | 
					     * @throws SignatureException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void updateContent(Message msg) throws SignatureException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sign the content that was added.
 | 
				
			||||||
 | 
					     * @return
 | 
				
			||||||
 | 
					     * @throws SignatureException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Signature sign() throws SignatureException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Initialize the verifier with the certificate whose Id is in sig.
 | 
				
			||||||
 | 
					     * @param sig
 | 
				
			||||||
 | 
					     * @throws CertificateException
 | 
				
			||||||
 | 
					     * @throws InvalidKeyException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void initVerify(Signature sig)
 | 
				
			||||||
 | 
					            throws CertificateException, InvalidKeyException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Verify the updated content using the initialized signature.
 | 
				
			||||||
 | 
					     * @return
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean verify();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Loads a private signing key. The keystore must include both the public and private
 | 
				
			||||||
 | 
					     * key parts.
 | 
				
			||||||
 | 
					     * This method must be called before calling {@link #sign(List)}
 | 
				
			||||||
 | 
					     * Calling this method again will replace the key.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param keyStoreBuilder A keystore builder that can be used to load a keystore.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
 | 
				
			||||||
 | 
					            throws IOException, CertificateException, UnrecoverableKeyException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Clear the signing key (will require authentication to use again).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void clearSigningKey();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean verify(Signature sig, List<Message> msgs);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,306 @@
 | 
				
			||||||
 | 
					package meerkat.crypto.concrete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
 | 
					import java.security.*;
 | 
				
			||||||
 | 
					import java.security.cert.*;
 | 
				
			||||||
 | 
					import java.security.cert.Certificate;
 | 
				
			||||||
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.protobuf.ByteString;
 | 
				
			||||||
 | 
					import meerkat.protobuf.Crypto;
 | 
				
			||||||
 | 
					import meerkat.util.Hex;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.protobuf.Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import meerkat.crypto.DigitalSignature;
 | 
				
			||||||
 | 
					import meerkat.protobuf.Crypto.Signature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.security.auth.callback.Callback;
 | 
				
			||||||
 | 
					import javax.security.auth.callback.CallbackHandler;
 | 
				
			||||||
 | 
					import javax.security.auth.callback.PasswordCallback;
 | 
				
			||||||
 | 
					import javax.security.auth.callback.UnsupportedCallbackException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sign and verify digital signatures.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This class is not thread-safe (each thread should have its own instance).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature {
 | 
				
			||||||
 | 
					    final Logger logger = LoggerFactory.getLogger(getClass());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final public static String KEYSTORE_TYPE = "PKCS12";
 | 
				
			||||||
 | 
					    final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SHA256Digest digest = new SHA256Digest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Buffer used to hold length in for hash update
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ByteBuffer lenBuf = ByteBuffer.allocate(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Map<ByteString, Certificate> loadedCertificates = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Signature currently loaded (will be used in calls to {@link #verify()}).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ByteString loadedSignature = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ByteString loadedSigningKeyId = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The actual signing implementation. (used for both signing and verifying)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    java.security.Signature signer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Compute a fingerprint of a cert as a SHA256 hash.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param cert
 | 
				
			||||||
 | 
					     * @return
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public ByteString computeCertificateFingerprint(Certificate cert) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            digest.reset();
 | 
				
			||||||
 | 
					            byte[] data = cert.getEncoded();
 | 
				
			||||||
 | 
					            digest.update(data);
 | 
				
			||||||
 | 
					            return ByteString.copyFrom(digest.digest());
 | 
				
			||||||
 | 
					        } catch (CertificateEncodingException e) {
 | 
				
			||||||
 | 
					            // Shouldn't happen
 | 
				
			||||||
 | 
					            logger.error("Certificate encoding error", e);
 | 
				
			||||||
 | 
					            return ByteString.EMPTY;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ECDSASignature(java.security.Signature signer) {
 | 
				
			||||||
 | 
					        this.signer = signer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ECDSASignature() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            this.signer = java.security.Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM);
 | 
				
			||||||
 | 
					        } catch (NoSuchAlgorithmException e) {
 | 
				
			||||||
 | 
					            // Should never happen
 | 
				
			||||||
 | 
					            logger.error("Couldn't find implementation for " + DEFAULT_SIGNATURE_ALGORITHM + " signatures", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadVerificationCertificates(InputStream certStream)
 | 
				
			||||||
 | 
					            throws CertificateException {
 | 
				
			||||||
 | 
					        CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509);
 | 
				
			||||||
 | 
					        Collection<? extends Certificate> certs = certificateFactory.generateCertificates(certStream);
 | 
				
			||||||
 | 
					        for (Certificate cert : certs) {
 | 
				
			||||||
 | 
					            // Just checking
 | 
				
			||||||
 | 
					            if (!(cert instanceof X509Certificate)) {
 | 
				
			||||||
 | 
					                logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName());
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            PublicKey pubKey = cert.getPublicKey();
 | 
				
			||||||
 | 
					            ByteString keyId = computeCertificateFingerprint(cert);
 | 
				
			||||||
 | 
					            loadedCertificates.put(keyId, cert);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void clearVerificationCertificates() {
 | 
				
			||||||
 | 
					        loadedCertificates.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add the list of messages to the stream that is being verified/signed.
 | 
				
			||||||
 | 
					     * Messages are prepended with their length in 32-bit big-endian format.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param msg
 | 
				
			||||||
 | 
					     * @throws SignatureException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void updateContent(Message msg) throws SignatureException {
 | 
				
			||||||
 | 
					        assert msg != null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lenBuf.clear();
 | 
				
			||||||
 | 
					        lenBuf.putInt(msg.getSerializedSize());
 | 
				
			||||||
 | 
					        lenBuf.flip();
 | 
				
			||||||
 | 
					        signer.update(lenBuf);
 | 
				
			||||||
 | 
					        signer.update(msg.toByteString().asReadOnlyByteBuffer());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void updateSigner(InputStream in) throws IOException, SignatureException {
 | 
				
			||||||
 | 
					        ByteString inStr = ByteString.readFrom(in);
 | 
				
			||||||
 | 
					        signer.update(inStr.asReadOnlyByteBuffer());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Signature sign() throws SignatureException {
 | 
				
			||||||
 | 
					        Signature.Builder sig = Signature.newBuilder();
 | 
				
			||||||
 | 
					        sig.setType(Crypto.SignatureType.ECDSA);
 | 
				
			||||||
 | 
					        sig.setData(ByteString.copyFrom(signer.sign()));
 | 
				
			||||||
 | 
					        sig.setSignerId(loadedSigningKeyId);
 | 
				
			||||||
 | 
					        return sig.build();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void initVerify(Signature sig)
 | 
				
			||||||
 | 
					            throws CertificateException, InvalidKeyException {
 | 
				
			||||||
 | 
					        Certificate cert = loadedCertificates.get(sig.getSignerId());
 | 
				
			||||||
 | 
					        if (cert == null) {
 | 
				
			||||||
 | 
					            logger.warn("No certificate loaded for ID {}!", sig.getSignerId());
 | 
				
			||||||
 | 
					            throw new CertificateException("No certificate loaded for " + sig.getSignerId());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        signer.initVerify(cert.getPublicKey());
 | 
				
			||||||
 | 
					        loadedSignature = sig.getData();
 | 
				
			||||||
 | 
					        loadedSigningKeyId = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean verify() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            return signer.verify(loadedSignature.toByteArray());
 | 
				
			||||||
 | 
					        } catch (SignatureException e) {
 | 
				
			||||||
 | 
					            // Happens only if signature is invalid!
 | 
				
			||||||
 | 
					            logger.error("Signature exception", e);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Utility method to more easily deal with simple password-protected files.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param password
 | 
				
			||||||
 | 
					     * @return
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public CallbackHandler getFixedPasswordHandler(final char[] password) {
 | 
				
			||||||
 | 
					        return new CallbackHandler() {
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
 | 
				
			||||||
 | 
					                for (Callback callback : callbacks) {
 | 
				
			||||||
 | 
					                    if (callback instanceof PasswordCallback) {
 | 
				
			||||||
 | 
					                        PasswordCallback passwordCallback = (PasswordCallback) callback;
 | 
				
			||||||
 | 
					                        logger.debug("Requested password ({})", passwordCallback.getPrompt());
 | 
				
			||||||
 | 
					                        passwordCallback.setPassword(password);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Load a keystore from an input stream in PKCS12 format.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param keyStream
 | 
				
			||||||
 | 
					     * @param password
 | 
				
			||||||
 | 
					     * @return
 | 
				
			||||||
 | 
					     * @throws IOException
 | 
				
			||||||
 | 
					     * @throws CertificateException
 | 
				
			||||||
 | 
					     * @throws KeyStoreException
 | 
				
			||||||
 | 
					     * @throws NoSuchAlgorithmException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
 | 
				
			||||||
 | 
					            throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
 | 
				
			||||||
 | 
					        KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
 | 
				
			||||||
 | 
					        keyStore.load(keyStream, password);
 | 
				
			||||||
 | 
					        return KeyStore.Builder.newInstance(keyStore, new KeyStore.CallbackHandlerProtection(getFixedPasswordHandler(password)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * For now we only support PKCS12.
 | 
				
			||||||
 | 
					     * TODO: Support for PKCS11 as well.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param keyStoreBuilder
 | 
				
			||||||
 | 
					     * @throws IOException
 | 
				
			||||||
 | 
					     * @throws CertificateException
 | 
				
			||||||
 | 
					     * @throws UnrecoverableKeyException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
 | 
				
			||||||
 | 
					            throws IOException, CertificateException, UnrecoverableKeyException {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            KeyStore keyStore = keyStoreBuilder.getKeyStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Iterate through all aliases until we find the first privatekey
 | 
				
			||||||
 | 
					            Enumeration<String> aliases = keyStore.aliases();
 | 
				
			||||||
 | 
					            while (aliases.hasMoreElements()) {
 | 
				
			||||||
 | 
					                String alias = aliases.nextElement();
 | 
				
			||||||
 | 
					                logger.trace("Testing keystore entry {}", alias);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    Certificate cert = keyStore.getCertificate(alias);
 | 
				
			||||||
 | 
					                    logger.trace("keystore entry {}, has cert type {}", alias, cert.getClass());
 | 
				
			||||||
 | 
					                    Key key;
 | 
				
			||||||
 | 
					                    try {
 | 
				
			||||||
 | 
					                        key = keyStore.getKey(alias, null);
 | 
				
			||||||
 | 
					                    } catch (UnrecoverableKeyException e) {
 | 
				
			||||||
 | 
					                        // This might be a keystore that doesn't support callback handlers
 | 
				
			||||||
 | 
					                        // (e.g., Java 8 PKCS12)
 | 
				
			||||||
 | 
					                        // Manually extract password using callback handler
 | 
				
			||||||
 | 
					                        char[] password = null;
 | 
				
			||||||
 | 
					                        KeyStore.ProtectionParameter prot = keyStoreBuilder.getProtectionParameter(alias);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (prot instanceof KeyStore.PasswordProtection) {
 | 
				
			||||||
 | 
					                            password = ((KeyStore.PasswordProtection) prot).getPassword();
 | 
				
			||||||
 | 
					                        } else if (prot instanceof KeyStore.CallbackHandlerProtection) {
 | 
				
			||||||
 | 
					                            PasswordCallback callback = new PasswordCallback("Password for " + alias + "?", false);
 | 
				
			||||||
 | 
					                            Callback[] callbacks = { callback };
 | 
				
			||||||
 | 
					                            try {
 | 
				
			||||||
 | 
					                                ((KeyStore.CallbackHandlerProtection) prot).getCallbackHandler().handle(callbacks);
 | 
				
			||||||
 | 
					                                password = callback.getPassword();
 | 
				
			||||||
 | 
					                            } catch (UnsupportedCallbackException e1) {
 | 
				
			||||||
 | 
					                                logger.error("PasswordCallback fallback not supported!", e1);
 | 
				
			||||||
 | 
					                                throw new UnrecoverableKeyException("Couldn't use password callback to get key");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            logger.error("Unrecognized protection handler for keystore: {}", prot.getClass());
 | 
				
			||||||
 | 
					                            throw new UnrecoverableKeyException("Unrecognized protection handler for keystore");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        key = keyStore.getKey(alias, password);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    logger.trace("keystore entry {}, has key type {}", alias, key.getClass());
 | 
				
			||||||
 | 
					                    if (key instanceof PrivateKey) {
 | 
				
			||||||
 | 
					                        loadedSigningKeyId = computeCertificateFingerprint(cert);
 | 
				
			||||||
 | 
					                        signer.initSign((PrivateKey) key);
 | 
				
			||||||
 | 
					                        logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId));
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        logger.info("Certificate {} in keystore does not have a private key", cert.toString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } catch(InvalidKeyException e) {
 | 
				
			||||||
 | 
					                    logger.info("Read invalid key", e);
 | 
				
			||||||
 | 
					                } catch(UnrecoverableEntryException e) {
 | 
				
			||||||
 | 
					                    logger.info("Read unrecoverable entry", e);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } catch (KeyStoreException e) {
 | 
				
			||||||
 | 
					            logger.error("Keystore exception", e);
 | 
				
			||||||
 | 
					        } catch (NoSuchAlgorithmException e) {
 | 
				
			||||||
 | 
					            logger.error("NoSuchAlgorithmException exception", e);
 | 
				
			||||||
 | 
					            throw new CertificateException(e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        logger.error("Didn't find valid private key entry in keystore");
 | 
				
			||||||
 | 
					        throw new UnrecoverableKeyException("Didn't find valid private key entry in keystore!");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void clearSigningKey() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // TODO: Check if this really clears the key from memory
 | 
				
			||||||
 | 
					            if (loadedSigningKeyId != null)
 | 
				
			||||||
 | 
					                signer.initSign(null);
 | 
				
			||||||
 | 
					            loadedSigningKeyId = null;
 | 
				
			||||||
 | 
					        } catch (InvalidKeyException e) {
 | 
				
			||||||
 | 
					            // Do nothing
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					package meerkat.crypto.concrete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bouncycastle.jce.provider.BouncyCastleProvider;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.security.Security;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A class that performs required crypto setup
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class GlobalCryptoSetup {
 | 
				
			||||||
 | 
					    final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static boolean loadedBouncyCastle = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static boolean hasSecp256k1Curve() {
 | 
				
			||||||
 | 
					        // For now we just check if the java version is at least 8
 | 
				
			||||||
 | 
					        String[] version = System.getProperty("java.version").split("\\.");
 | 
				
			||||||
 | 
					        int major = Integer.parseInt(version[0]);
 | 
				
			||||||
 | 
					        int minor = Integer.parseInt(version[1]);
 | 
				
			||||||
 | 
					        return ((major > 1) || ((major > 0) && (minor > 7)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void doSetup() {
 | 
				
			||||||
 | 
					        // Make bouncycastle our default provider if we're running on a JVM version < 8
 | 
				
			||||||
 | 
					        // (earlier version don't support the EC curve we use for signatures)
 | 
				
			||||||
 | 
					        if (!hasSecp256k1Curve() && !loadedBouncyCastle) {
 | 
				
			||||||
 | 
					            loadedBouncyCastle = true;
 | 
				
			||||||
 | 
					            Security.insertProviderAt(new BouncyCastleProvider(), 1);
 | 
				
			||||||
 | 
					            logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public GlobalCryptoSetup() {
 | 
				
			||||||
 | 
					        doSetup();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,29 @@
 | 
				
			||||||
package meerkat.crypto.concrete;
 | 
					package meerkat.crypto.concrete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.protobuf.ByteString;
 | 
				
			||||||
import com.google.protobuf.Message;
 | 
					import com.google.protobuf.Message;
 | 
				
			||||||
import meerkat.crypto.Digest;
 | 
					import meerkat.crypto.Digest;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
import java.security.MessageDigest;
 | 
					import java.security.MessageDigest;
 | 
				
			||||||
import java.security.NoSuchAlgorithmException;
 | 
					import java.security.NoSuchAlgorithmException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Created by talm on 11/9/15.
 | 
					 * Created by talm on 11/9/15.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class SHA256Digest implements Digest {
 | 
					public class SHA256Digest extends GlobalCryptoSetup implements Digest {
 | 
				
			||||||
    final Logger logger = LoggerFactory.getLogger(getClass());
 | 
					    final Logger logger = LoggerFactory.getLogger(getClass());
 | 
				
			||||||
    public static final String SHA256 = "SHA-256";
 | 
					    public static final String SHA256 = "SHA-256";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MessageDigest hash;
 | 
					    MessageDigest hash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Used to convert length to bytes in proper order.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ByteBuffer lenBuf = ByteBuffer.allocate(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Instantiate with a specified algorithm.
 | 
					     * Instantiate with a specified algorithm.
 | 
				
			||||||
     * @param algorithm
 | 
					     * @param algorithm
 | 
				
			||||||
| 
						 | 
					@ -32,7 +39,7 @@ public class SHA256Digest implements Digest {
 | 
				
			||||||
    public SHA256Digest() { this(true); }
 | 
					    public SHA256Digest() { this(true); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**SHA
 | 
				
			||||||
     * Instantiate with the default (SHA-256) algorithm,
 | 
					     * Instantiate with the default (SHA-256) algorithm,
 | 
				
			||||||
     * or create an empty class (for cloning)
 | 
					     * or create an empty class (for cloning)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
| 
						 | 
					@ -55,9 +62,22 @@ public class SHA256Digest implements Digest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void update(Message msg) {
 | 
					    public void update(Message msg) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lenBuf.clear();
 | 
				
			||||||
 | 
					        lenBuf.putInt(msg.getSerializedSize());
 | 
				
			||||||
 | 
					        lenBuf.flip();
 | 
				
			||||||
 | 
					        hash.update(lenBuf);
 | 
				
			||||||
        hash.update(msg.toByteString().asReadOnlyByteBuffer());
 | 
					        hash.update(msg.toByteString().asReadOnlyByteBuffer());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final public void update(ByteString msg) {
 | 
				
			||||||
 | 
					        hash.update(msg.asReadOnlyByteBuffer());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final public void update(byte[] msg) {
 | 
				
			||||||
 | 
					        hash.update(msg);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void reset() {
 | 
					    public void reset() {
 | 
				
			||||||
        hash.reset();
 | 
					        hash.reset();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					package meerkat.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.protobuf.ByteString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Convert to/from Hex
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Hex {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Encode a {@link ByteString}  as a hex string.
 | 
				
			||||||
 | 
					     * @param str
 | 
				
			||||||
 | 
					     * @return
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static String encode(ByteString str) {
 | 
				
			||||||
 | 
					        StringBuilder s = new StringBuilder();
 | 
				
			||||||
 | 
					        for (byte b : str) {
 | 
				
			||||||
 | 
					            s.append(Integer.toHexString(((int) b) & 0xff));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return s.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String encode(byte[] bytes) {
 | 
				
			||||||
 | 
					        return encode(ByteString.copyFrom(bytes));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,14 +13,18 @@ enum SignatureType {
 | 
				
			||||||
message Signature {
 | 
					message Signature {
 | 
				
			||||||
    SignatureType type = 1;
 | 
					    SignatureType type = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Data encoding depends on type; default is x509 BER-encoded
 | 
					    // Data encoding depends on type; default is DER-encoded
 | 
				
			||||||
    bytes data = 2;
 | 
					    bytes data = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ID of the signer (should be the fingerprint of the signature verification key)
 | 
				
			||||||
 | 
					    bytes signer_id = 3;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Public key used to verify signatures
 | 
					// Public key used to verify signatures
 | 
				
			||||||
message SignatureVerificationKey {
 | 
					message SignatureVerificationKey {
 | 
				
			||||||
    SignatureType type = 1;
 | 
					    SignatureType type = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Data encoding depends on type; default is x509 DER-encoded
 | 
				
			||||||
    bytes data = 2;
 | 
					    bytes data = 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import ch.qos.logback.classic.encoder.PatternLayoutEncoder
 | 
				
			||||||
 | 
					import ch.qos.logback.classic.filter.ThresholdFilter
 | 
				
			||||||
 | 
					import ch.qos.logback.core.ConsoleAppender
 | 
				
			||||||
 | 
					import ch.qos.logback.core.util.Duration
 | 
				
			||||||
 | 
					import static ch.qos.logback.classic.Level.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (System.getProperty("log.debug") != null) {
 | 
				
			||||||
 | 
						println "Logback configuration debugging enabled"
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						statusListener(OnConsoleStatusListener)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def LOG_LEVEL = toLevel(System.getProperty("log.level"), INFO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def haveBeagle = System.getProperty("log.beagle") != null 
 | 
				
			||||||
 | 
					def logOps = System.getProperty("log.ops") != null  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					appender("CONSOLE", ConsoleAppender) {
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						filter(ThresholdFilter) {
 | 
				
			||||||
 | 
						  level = toLevel(System.getProperty("log.level"), TRACE)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						encoder(PatternLayoutEncoder) {
 | 
				
			||||||
 | 
						  pattern = "%d{HH:mm:ss.SSS} [%thread %file:%line] %-5level %logger{0} - %msg%n"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def appenders = [ "CONSOLE" ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (haveBeagle) {
 | 
				
			||||||
 | 
						appender("SOCKET", SocketAppender) {
 | 
				
			||||||
 | 
						  includeCallerData = true
 | 
				
			||||||
 | 
						  remoteHost = "localhost"
 | 
				
			||||||
 | 
						  port = 4321
 | 
				
			||||||
 | 
						  reconnectionDelay = new Duration(10000)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						appenders += ["SOCKET"]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					root(LOG_LEVEL, appenders)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,172 @@
 | 
				
			||||||
 | 
					package meerkat.crypto.concrete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.protobuf.ByteString;
 | 
				
			||||||
 | 
					import meerkat.protobuf.Crypto;
 | 
				
			||||||
 | 
					import meerkat.protobuf.Voting;
 | 
				
			||||||
 | 
					import org.junit.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayInputStream;
 | 
				
			||||||
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.security.KeyStore;
 | 
				
			||||||
 | 
					import java.util.Arrays;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertFalse;
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertTrue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Created by talm on 12/11/15.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class TestECDSASignature {
 | 
				
			||||||
 | 
					    public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12";
 | 
				
			||||||
 | 
					    public static String KEYFILE_PASSWORD = "secret";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt";
 | 
				
			||||||
 | 
					    public static String CERT2_DER_EXAMPLE = "/certs/enduser-certs/user2.der";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String MSG_PLAINTEXT_EXAMPLE = "/certs/signed-messages/helloworld.txt";
 | 
				
			||||||
 | 
					    public static String MSG_SIG_EXAMPLE = "/certs/signed-messages/helloworld.txt.sha256sig";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String HELLO_WORLD = "hello world!";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void loadSignatureKey() throws Exception {
 | 
				
			||||||
 | 
					        InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
 | 
				
			||||||
 | 
					        char[] password = KEYFILE_PASSWORD.toCharArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECDSASignature sig = new ECDSASignature();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        KeyStore.Builder keyStore = sig.getPKCS12KeyStoreBuilder(keyStream, password);
 | 
				
			||||||
 | 
					        sig.loadSigningCertificate(keyStore);
 | 
				
			||||||
 | 
					        keyStream.close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void loadPEMVerificationKey() throws Exception {
 | 
				
			||||||
 | 
					        InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECDSASignature sig = new ECDSASignature();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sig.loadVerificationCertificates(certStream);
 | 
				
			||||||
 | 
					        certStream.close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void loadDERVerificationKey() throws Exception {
 | 
				
			||||||
 | 
					        InputStream certStream = getClass().getResourceAsStream(CERT2_DER_EXAMPLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECDSASignature sig = new ECDSASignature();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sig.loadVerificationCertificates(certStream);
 | 
				
			||||||
 | 
					        certStream.close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void verifyValidSig() throws Exception {
 | 
				
			||||||
 | 
					        InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
 | 
				
			||||||
 | 
					        InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
 | 
				
			||||||
 | 
					        InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECDSASignature signer = new ECDSASignature();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signer.loadVerificationCertificates(certStream);
 | 
				
			||||||
 | 
					        certStream.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
 | 
				
			||||||
 | 
					        sig.setType(Crypto.SignatureType.ECDSA);
 | 
				
			||||||
 | 
					        sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
 | 
				
			||||||
 | 
					        sig.setData(ByteString.readFrom(sigStream));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Crypto.Signature builtSig = sig.build();
 | 
				
			||||||
 | 
					        signer.initVerify(builtSig);
 | 
				
			||||||
 | 
					        signer.updateSigner(msgStream);
 | 
				
			||||||
 | 
					        assertTrue("Signature did not verify!", signer.verify());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void verifyInvalidSig() throws Exception {
 | 
				
			||||||
 | 
					        InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
 | 
				
			||||||
 | 
					        InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
 | 
				
			||||||
 | 
					        InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECDSASignature signer = new ECDSASignature();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signer.loadVerificationCertificates(certStream);
 | 
				
			||||||
 | 
					        certStream.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
 | 
				
			||||||
 | 
					        sig.setType(Crypto.SignatureType.ECDSA);
 | 
				
			||||||
 | 
					        sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
 | 
				
			||||||
 | 
					        byte[] sigData = ByteString.readFrom(sigStream).toByteArray();
 | 
				
			||||||
 | 
					        ++sigData[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sig.setData(ByteString.copyFrom(sigData));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Crypto.Signature builtSig = sig.build();
 | 
				
			||||||
 | 
					        signer.initVerify(builtSig);
 | 
				
			||||||
 | 
					        signer.updateSigner(msgStream);
 | 
				
			||||||
 | 
					        assertFalse("Bad Signature passed verification!", signer.verify());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void verifyInvalidMsg() throws Exception {
 | 
				
			||||||
 | 
					        InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
 | 
				
			||||||
 | 
					        InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
 | 
				
			||||||
 | 
					        InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECDSASignature signer = new ECDSASignature();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signer.loadVerificationCertificates(certStream);
 | 
				
			||||||
 | 
					        certStream.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
 | 
				
			||||||
 | 
					        sig.setType(Crypto.SignatureType.ECDSA);
 | 
				
			||||||
 | 
					        sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
 | 
				
			||||||
 | 
					        sig.setData(ByteString.readFrom(sigStream));
 | 
				
			||||||
 | 
					        byte[] msgData = ByteString.readFrom(msgStream).toByteArray();
 | 
				
			||||||
 | 
					        ++msgData[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Crypto.Signature builtSig = sig.build();
 | 
				
			||||||
 | 
					        signer.initVerify(builtSig);
 | 
				
			||||||
 | 
					        signer.updateSigner(msgStream);
 | 
				
			||||||
 | 
					        assertFalse("Signature doesn't match message but passed verification!", signer.verify());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    public void signAndVerify() throws Exception {
 | 
				
			||||||
 | 
					        InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
 | 
				
			||||||
 | 
					        char[] password = KEYFILE_PASSWORD.toCharArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECDSASignature signer = new ECDSASignature();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password);
 | 
				
			||||||
 | 
					        signer.loadSigningCertificate(keyStore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Voting.UnsignedBulletinBoardMessage.Builder unsignedMsgBuilder = Voting.UnsignedBulletinBoardMessage.newBuilder();
 | 
				
			||||||
 | 
					        unsignedMsgBuilder.setData(ByteString.copyFromUtf8(HELLO_WORLD));
 | 
				
			||||||
 | 
					        unsignedMsgBuilder.addTags("Tag1");
 | 
				
			||||||
 | 
					        unsignedMsgBuilder.addTags("Tag2");
 | 
				
			||||||
 | 
					        unsignedMsgBuilder.addTags("Tag3");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Voting.UnsignedBulletinBoardMessage usMsg = unsignedMsgBuilder.build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signer.updateContent(usMsg);
 | 
				
			||||||
 | 
					        Crypto.Signature sig = signer.sign();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signer.initVerify(sig);
 | 
				
			||||||
 | 
					        signer.updateContent(usMsg);
 | 
				
			||||||
 | 
					        assertTrue("Couldn't verify signature on ", signer.verify());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					Certs and private keys for testing generated using OpenSSL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.crt and .pem files are in PEM format
 | 
				
			||||||
 | 
					.der files are in binary DER format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					files that have a name of the form *-with-password-xxxx.pem are encrypted with the password xxxx
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					-----BEGIN EC PRIVATE KEY-----
 | 
				
			||||||
 | 
					Proc-Type: 4,ENCRYPTED
 | 
				
			||||||
 | 
					DEK-Info: AES-256-CBC,243D718A0D80C59590E582A26E87A49C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RG6ITUTIdbJdWYX57oMn3tTCzHJSTjXAIZLjoVxy/v4UFYjluaFhGonIlbH1q2pP
 | 
				
			||||||
 | 
					ueu29Q3eT6144ypB8ARUJ1x0kRX1OL9zNHgdF9ulrCf9/nhGyC2nL+tHZ0YPbxoQ
 | 
				
			||||||
 | 
					+6yCQcRWvjUXLVzPEUnwMuHXJDpaXES8X0R4CISQKIA=
 | 
				
			||||||
 | 
					-----END EC PRIVATE KEY-----
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					-----BEGIN PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQge8JqCoaLoZq61aQki5Xm
 | 
				
			||||||
 | 
					GppcfAAkhHDGNQw/wLof5LmhRANCAAQJD1kW6BsNkRY9tslaugpOJOaoKX4uBz4S
 | 
				
			||||||
 | 
					Q96lPaPWkatNVgQchwNeB/hdjZwNuwE7A7XAwr69HFmhXRhsM005
 | 
				
			||||||
 | 
					-----END PRIVATE KEY-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					-----BEGIN PUBLIC KEY-----
 | 
				
			||||||
 | 
					MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugbDZEWPbbJWroKTiTmqCl+Lgc+
 | 
				
			||||||
 | 
					EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+vRxZoV0YbDNNOQ==
 | 
				
			||||||
 | 
					-----END PUBLIC KEY-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIDFjCCArygAwIBAgICEAAwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
 | 
				
			||||||
 | 
					YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
 | 
				
			||||||
 | 
					MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
 | 
				
			||||||
 | 
					ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MTM1NFoXDTI1MTEwODE2MTM1
 | 
				
			||||||
 | 
					NFowbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDExEzARBgNVBAgMClNvbWUt
 | 
				
			||||||
 | 
					U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
 | 
				
			||||||
 | 
					BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugb
 | 
				
			||||||
 | 
					DZEWPbbJWroKTiTmqCl+Lgc+EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+
 | 
				
			||||||
 | 
					vRxZoV0YbDNNOaOCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFLamS8o2
 | 
				
			||||||
 | 
					hFNd0vWy/irEBNWVNwFXMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
 | 
				
			||||||
 | 
					MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
 | 
				
			||||||
 | 
					N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
 | 
				
			||||||
 | 
					YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
 | 
				
			||||||
 | 
					LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
 | 
				
			||||||
 | 
					BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
 | 
				
			||||||
 | 
					A0gAMEUCIQD6QbhNNmB3AVVqhmXuiLA7WF6raShw6n0g/VloVGQebQIgEvxYclpO
 | 
				
			||||||
 | 
					MMynt5wH6X65rtn4Q1EGaDMvNbFweCDsldk=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE REQUEST-----
 | 
				
			||||||
 | 
					MIIBOjCB4QIBADCBgTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx
 | 
				
			||||||
 | 
					ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
 | 
				
			||||||
 | 
					BAsMDk1lZXJrYXQgVm90aW5nMRowGAYDVQQDDBFQb2xsaW5nIFN0YXRpb24gMTBW
 | 
				
			||||||
 | 
					MBAGByqGSM49AgEGBSuBBAAKA0IABAkPWRboGw2RFj22yVq6Ck4k5qgpfi4HPhJD
 | 
				
			||||||
 | 
					3qU9o9aRq01WBByHA14H+F2NnA27ATsDtcDCvr0cWaFdGGwzTTmgADAKBggqhkjO
 | 
				
			||||||
 | 
					PQQDAgNIADBFAiEA8gmIhALr7O5M1QLReGH3jheildTIr1mDWl14WyMf9U4CIF23
 | 
				
			||||||
 | 
					mInyo4VqNHLzxMLg5Cn3Oddokng3OXa63y4nTfv+
 | 
				
			||||||
 | 
					-----END CERTIFICATE REQUEST-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					-----BEGIN PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgYpBEO+XWm/n6VPeMVK76
 | 
				
			||||||
 | 
					mrZkDTpiwLsDykG7M4fU5RKhRANCAAR71/kVGyA3hdxcLBBT3NPQF6R3LholmLRN
 | 
				
			||||||
 | 
					qhnvHqzJWuy7ev+Xbuxtt9AN0ajyeFDy8Oe1bUSidnLyQi+nXC0f
 | 
				
			||||||
 | 
					-----END PRIVATE KEY-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					-----BEGIN PUBLIC KEY-----
 | 
				
			||||||
 | 
					MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsgN4XcXCwQU9zT0Bekdy4aJZi0
 | 
				
			||||||
 | 
					TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1EonZy8kIvp1wtHw==
 | 
				
			||||||
 | 
					-----END PUBLIC KEY-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIDFjCCArygAwIBAgICEAEwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
 | 
				
			||||||
 | 
					YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
 | 
				
			||||||
 | 
					MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
 | 
				
			||||||
 | 
					ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MjAzM1oXDTI1MTEwODE2MjAz
 | 
				
			||||||
 | 
					M1owbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDIxEzARBgNVBAgMClNvbWUt
 | 
				
			||||||
 | 
					U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
 | 
				
			||||||
 | 
					BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsg
 | 
				
			||||||
 | 
					N4XcXCwQU9zT0Bekdy4aJZi0TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1E
 | 
				
			||||||
 | 
					onZy8kIvp1wtH6OCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKCdquYj
 | 
				
			||||||
 | 
					DGHqAHt+4PIDlw0h2UvuMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
 | 
				
			||||||
 | 
					MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
 | 
				
			||||||
 | 
					N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
 | 
				
			||||||
 | 
					YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
 | 
				
			||||||
 | 
					LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
 | 
				
			||||||
 | 
					BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
 | 
				
			||||||
 | 
					A0gAMEUCIQDpo5B0vvEJSax3YzOMfE8l0pfDUIKLdBWJVGeq0VLtIgIgVr0+4/0e
 | 
				
			||||||
 | 
					n+R+l1OVOLh2GirloOgbv5Ch5BQ2pQNAG2Y=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE REQUEST-----
 | 
				
			||||||
 | 
					MIIBOzCB4QIBADCBgTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx
 | 
				
			||||||
 | 
					ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
 | 
				
			||||||
 | 
					BAsMDk1lZXJrYXQgVm90aW5nMRowGAYDVQQDDBFQb2xsaW5nIFN0YXRpb24gMjBW
 | 
				
			||||||
 | 
					MBAGByqGSM49AgEGBSuBBAAKA0IABHvX+RUbIDeF3FwsEFPc09AXpHcuGiWYtE2q
 | 
				
			||||||
 | 
					Ge8erMla7Lt6/5du7G230A3RqPJ4UPLw57VtRKJ2cvJCL6dcLR+gADAKBggqhkjO
 | 
				
			||||||
 | 
					PQQDAgNJADBGAiEA6Ls/ojRaZT+u4YeOBYcPbRcJE3jSTe1Sm/lR7fDyEhMCIQCk
 | 
				
			||||||
 | 
					UOca+e2b8+CqM3CURBv6TqUMmZ3HeMRvEAxFPqOWSw==
 | 
				
			||||||
 | 
					-----END CERTIFICATE REQUEST-----
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIDFjCCArygAwIBAgICEAAwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
 | 
				
			||||||
 | 
					YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
 | 
				
			||||||
 | 
					MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
 | 
				
			||||||
 | 
					ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MTM1NFoXDTI1MTEwODE2MTM1
 | 
				
			||||||
 | 
					NFowbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDExEzARBgNVBAgMClNvbWUt
 | 
				
			||||||
 | 
					U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
 | 
				
			||||||
 | 
					BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECQ9ZFugb
 | 
				
			||||||
 | 
					DZEWPbbJWroKTiTmqCl+Lgc+EkPepT2j1pGrTVYEHIcDXgf4XY2cDbsBOwO1wMK+
 | 
				
			||||||
 | 
					vRxZoV0YbDNNOaOCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFLamS8o2
 | 
				
			||||||
 | 
					hFNd0vWy/irEBNWVNwFXMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
 | 
				
			||||||
 | 
					MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
 | 
				
			||||||
 | 
					N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
 | 
				
			||||||
 | 
					YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
 | 
				
			||||||
 | 
					LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
 | 
				
			||||||
 | 
					BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
 | 
				
			||||||
 | 
					A0gAMEUCIQD6QbhNNmB3AVVqhmXuiLA7WF6raShw6n0g/VloVGQebQIgEvxYclpO
 | 
				
			||||||
 | 
					MMynt5wH6X65rtn4Q1EGaDMvNbFweCDsldk=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIDFjCCArygAwIBAgICEAEwCgYIKoZIzj0EAwIwgYIxKTAnBgNVBAMMIE1lZXJr
 | 
				
			||||||
 | 
					YXQgVm90aW5nIEludGVybWVkaWF0ZSBDQSAxMRMwEQYDVQQIDApTb21lLVN0YXRl
 | 
				
			||||||
 | 
					MQswCQYDVQQGEwJJTDEVMBMGA1UECgwMSURDIEhlcnpsaXlhMRwwGgYDVQQLDBNN
 | 
				
			||||||
 | 
					ZWVya2F0IFZvdGluZyBUZWFtMB4XDTE1MTExMTE2MjAzM1oXDTI1MTEwODE2MjAz
 | 
				
			||||||
 | 
					M1owbjEaMBgGA1UEAwwRUG9sbGluZyBTdGF0aW9uIDIxEzARBgNVBAgMClNvbWUt
 | 
				
			||||||
 | 
					U3RhdGUxCzAJBgNVBAYTAklMMRUwEwYDVQQKDAxJREMgSGVyemxpeWExFzAVBgNV
 | 
				
			||||||
 | 
					BAsMDk1lZXJrYXQgVm90aW5nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEe9f5FRsg
 | 
				
			||||||
 | 
					N4XcXCwQU9zT0Bekdy4aJZi0TaoZ7x6syVrsu3r/l27sbbfQDdGo8nhQ8vDntW1E
 | 
				
			||||||
 | 
					onZy8kIvp1wtH6OCATYwggEyMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKCdquYj
 | 
				
			||||||
 | 
					DGHqAHt+4PIDlw0h2UvuMB8GA1UdIwQYMBaAFBeyv0c75eT6PNumHo9TZ2B9vtcp
 | 
				
			||||||
 | 
					MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATBEBgNVHR8EPTA7MDmg
 | 
				
			||||||
 | 
					N6A1hjNodHRwOi8vY3JsLmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRp
 | 
				
			||||||
 | 
					YXRlMS5jcmwwegYIKwYBBQUHAQEEbjBsMEEGCCsGAQUFBzAChjVodHRwOi8vcGtp
 | 
				
			||||||
 | 
					LmZhY3RjZW50ZXIub3JnL21lZXJrYXQtaW50ZXJtZWRpYXRlLWNhLmNydDAnBggr
 | 
				
			||||||
 | 
					BgEFBQcwAYYbaHR0cDovL29jc3AuZmFjdGNlbnRlci5vcmcvMAoGCCqGSM49BAMC
 | 
				
			||||||
 | 
					A0gAMEUCIQDpo5B0vvEJSax3YzOMfE8l0pfDUIKLdBWJVGeq0VLtIgIgVr0+4/0e
 | 
				
			||||||
 | 
					n+R+l1OVOLh2GirloOgbv5Ch5BQ2pQNAG2Y=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					V	251108161354Z		1000	unknown	/CN=Polling Station 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting
 | 
				
			||||||
 | 
					V	251108162033Z		1001	unknown	/CN=Polling Station 2/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					unique_subject = no
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					unique_subject = no
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					V	251108161354Z		1000	unknown	/CN=Polling Station 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					1002
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					1001
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					1000
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					-----BEGIN PRIVATE KEY-----
 | 
				
			||||||
 | 
					MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgJvMhOfcQfdK/42QlBbri
 | 
				
			||||||
 | 
					IYXLM/gVHq/yppOykDqB3s6hRANCAAQoShAtCGW5c9pk/4/sKN1qjCgDKngqJpba
 | 
				
			||||||
 | 
					kku6cIDqXDr+aHsl+/KdSHd46OI3fEynl+/Pc85wRsaY6Z7b1PdS
 | 
				
			||||||
 | 
					-----END PRIVATE KEY-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIDfDCCAyGgAwIBAgICEAAwCgYIKoZIzj0EAwIwgbAxCzAJBgNVBAYTAklMMRMw
 | 
				
			||||||
 | 
					EQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQHDAhIZXJ6bGl5YTEUMBIGA1UECgwL
 | 
				
			||||||
 | 
					SURDIEhlcmxpeWExHzAdBgNVBAsMFk1lZXJrYXQgVm90aW5nIFByb2plY3QxGDAW
 | 
				
			||||||
 | 
					BgNVBAMMD1Rlc3RpbmcgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZdGVzdGluZy1j
 | 
				
			||||||
 | 
					YUBmYWN0Y2VudGVyLm9yZzAeFw0xNTExMTExNjA4MDJaFw0yNTExMDgxNjA4MDJa
 | 
				
			||||||
 | 
					MIGCMSkwJwYDVQQDDCBNZWVya2F0IFZvdGluZyBJbnRlcm1lZGlhdGUgQ0EgMTET
 | 
				
			||||||
 | 
					MBEGA1UECAwKU29tZS1TdGF0ZTELMAkGA1UEBhMCSUwxFTATBgNVBAoMDElEQyBI
 | 
				
			||||||
 | 
					ZXJ6bGl5YTEcMBoGA1UECwwTTWVlcmthdCBWb3RpbmcgVGVhbTBWMBAGByqGSM49
 | 
				
			||||||
 | 
					AgEGBSuBBAAKA0IABChKEC0IZblz2mT/j+wo3WqMKAMqeComltqSS7pwgOpcOv5o
 | 
				
			||||||
 | 
					eyX78p1Id3jo4jd8TKeX789zznBGxpjpntvU91KjggFYMIIBVDAPBgNVHRMBAf8E
 | 
				
			||||||
 | 
					BTADAQH/MB0GA1UdDgQWBBQXsr9HO+Xk+jzbph6PU2dgfb7XKTAfBgNVHSMEGDAW
 | 
				
			||||||
 | 
					gBSJD9L1fLmX4A9CBoLsYXn3OPy1ojALBgNVHQ8EBAMCAaYwEwYDVR0lBAwwCgYI
 | 
				
			||||||
 | 
					KwYBBQUHAwEwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5mYWN0Y2VudGVy
 | 
				
			||||||
 | 
					Lm9yZy9tZWVya2F0LXJvb3QtY2EuY3JsMCsGA1UdEQQkMCKCIE1lZXJrYXQgVm90
 | 
				
			||||||
 | 
					aW5nIEludGVybWVkaWF0ZSBDQSAxMHIGCCsGAQUFBwEBBGYwZDA5BggrBgEFBQcw
 | 
				
			||||||
 | 
					AoYtaHR0cDovL3BraS5mYWN0Y2VudGVyLm9yZy9tZWVya2F0LXJvb3QtY2EuY3J0
 | 
				
			||||||
 | 
					MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5mYWN0Y2VudGVyLm9yZy8wCgYIKoZI
 | 
				
			||||||
 | 
					zj0EAwIDSQAwRgIhALEMHq2ssC9rLXiG8v6NcZetwwxdu3B3LW9s0KeGoNIEAiEA
 | 
				
			||||||
 | 
					skA56tMnhiZe38msyanRyRrAHyBI2fGs6GP3UBrg2P8=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE REQUEST-----
 | 
				
			||||||
 | 
					MIIBTTCB9QIBADCBlTELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUx
 | 
				
			||||||
 | 
					ETAPBgNVBAcMCEhlcnpsaXlhMRUwEwYDVQQKDAxJREMgSGVyemxpeWExHDAaBgNV
 | 
				
			||||||
 | 
					BAsME01lZXJrYXQgVm90aW5nIFRlYW0xKTAnBgNVBAMMIE1lZXJrYXQgVm90aW5n
 | 
				
			||||||
 | 
					IEludGVybWVkaWF0ZSBDQSAxMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKEoQLQhl
 | 
				
			||||||
 | 
					uXPaZP+P7CjdaowoAyp4KiaW2pJLunCA6lw6/mh7JfvynUh3eOjiN3xMp5fvz3PO
 | 
				
			||||||
 | 
					cEbGmOme29T3UqAAMAoGCCqGSM49BAMCA0cAMEQCIFlyJO5NFqnMUu5hOlQa872E
 | 
				
			||||||
 | 
					yy0V3zkqeN6Aly+LtEQqAiAfHwbi1lkJOZT2tOX8gfJzcac2jKmbgIhmITNq7uma
 | 
				
			||||||
 | 
					Wg==
 | 
				
			||||||
 | 
					-----END CERTIFICATE REQUEST-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					[ ca ]
 | 
				
			||||||
 | 
					default_ca = myca
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ crl_ext ]
 | 
				
			||||||
 | 
					issuerAltName=issuer:copy 
 | 
				
			||||||
 | 
					authorityKeyIdentifier=keyid:always
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ myca ]
 | 
				
			||||||
 | 
					 dir = ./
 | 
				
			||||||
 | 
					 new_certs_dir = $dir
 | 
				
			||||||
 | 
					 unique_subject = no
 | 
				
			||||||
 | 
					 certificate = $dir/intermediate-ca-1.crt
 | 
				
			||||||
 | 
					 database = $dir/certindex
 | 
				
			||||||
 | 
					 private_key = $dir/intermediate-ca-1-private-key.pem
 | 
				
			||||||
 | 
					 serial = $dir/certserial
 | 
				
			||||||
 | 
					 default_days = 3650
 | 
				
			||||||
 | 
					 default_md = sha256
 | 
				
			||||||
 | 
					 policy = myca_policy
 | 
				
			||||||
 | 
					 x509_extensions = myca_extensions
 | 
				
			||||||
 | 
					 crlnumber = $dir/crlnumber
 | 
				
			||||||
 | 
					 default_crl_days = 3650
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ myca_policy ]
 | 
				
			||||||
 | 
					 commonName = supplied
 | 
				
			||||||
 | 
					 stateOrProvinceName = optional
 | 
				
			||||||
 | 
					 countryName = optional
 | 
				
			||||||
 | 
					 emailAddress = optional
 | 
				
			||||||
 | 
					 organizationName = supplied
 | 
				
			||||||
 | 
					 organizationalUnitName = optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ myca_extensions ]
 | 
				
			||||||
 | 
					 basicConstraints = critical,CA:FALSE
 | 
				
			||||||
 | 
					 keyUsage = critical,any
 | 
				
			||||||
 | 
					 subjectKeyIdentifier = hash
 | 
				
			||||||
 | 
					 authorityKeyIdentifier = keyid:always,issuer
 | 
				
			||||||
 | 
					 keyUsage = digitalSignature,keyEncipherment
 | 
				
			||||||
 | 
					 extendedKeyUsage = serverAuth
 | 
				
			||||||
 | 
					 crlDistributionPoints = @crl_section
 | 
				
			||||||
 | 
					 authorityInfoAccess = @ocsp_section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [crl_section]
 | 
				
			||||||
 | 
					 URI.0 = http://crl.factcenter.org/meerkat-intermediate1.crl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ocsp_section]
 | 
				
			||||||
 | 
					 caIssuers;URI.0 = http://pki.factcenter.org/meerkat-intermediate-ca.crt
 | 
				
			||||||
 | 
					 OCSP;URI.0 = http://ocsp.factcenter.org/
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIDfDCCAyGgAwIBAgICEAAwCgYIKoZIzj0EAwIwgbAxCzAJBgNVBAYTAklMMRMw
 | 
				
			||||||
 | 
					EQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQHDAhIZXJ6bGl5YTEUMBIGA1UECgwL
 | 
				
			||||||
 | 
					SURDIEhlcmxpeWExHzAdBgNVBAsMFk1lZXJrYXQgVm90aW5nIFByb2plY3QxGDAW
 | 
				
			||||||
 | 
					BgNVBAMMD1Rlc3RpbmcgUm9vdCBDQTEoMCYGCSqGSIb3DQEJARYZdGVzdGluZy1j
 | 
				
			||||||
 | 
					YUBmYWN0Y2VudGVyLm9yZzAeFw0xNTExMTExNjA4MDJaFw0yNTExMDgxNjA4MDJa
 | 
				
			||||||
 | 
					MIGCMSkwJwYDVQQDDCBNZWVya2F0IFZvdGluZyBJbnRlcm1lZGlhdGUgQ0EgMTET
 | 
				
			||||||
 | 
					MBEGA1UECAwKU29tZS1TdGF0ZTELMAkGA1UEBhMCSUwxFTATBgNVBAoMDElEQyBI
 | 
				
			||||||
 | 
					ZXJ6bGl5YTEcMBoGA1UECwwTTWVlcmthdCBWb3RpbmcgVGVhbTBWMBAGByqGSM49
 | 
				
			||||||
 | 
					AgEGBSuBBAAKA0IABChKEC0IZblz2mT/j+wo3WqMKAMqeComltqSS7pwgOpcOv5o
 | 
				
			||||||
 | 
					eyX78p1Id3jo4jd8TKeX789zznBGxpjpntvU91KjggFYMIIBVDAPBgNVHRMBAf8E
 | 
				
			||||||
 | 
					BTADAQH/MB0GA1UdDgQWBBQXsr9HO+Xk+jzbph6PU2dgfb7XKTAfBgNVHSMEGDAW
 | 
				
			||||||
 | 
					gBSJD9L1fLmX4A9CBoLsYXn3OPy1ojALBgNVHQ8EBAMCAaYwEwYDVR0lBAwwCgYI
 | 
				
			||||||
 | 
					KwYBBQUHAwEwPgYDVR0fBDcwNTAzoDGgL4YtaHR0cDovL2NybC5mYWN0Y2VudGVy
 | 
				
			||||||
 | 
					Lm9yZy9tZWVya2F0LXJvb3QtY2EuY3JsMCsGA1UdEQQkMCKCIE1lZXJrYXQgVm90
 | 
				
			||||||
 | 
					aW5nIEludGVybWVkaWF0ZSBDQSAxMHIGCCsGAQUFBwEBBGYwZDA5BggrBgEFBQcw
 | 
				
			||||||
 | 
					AoYtaHR0cDovL3BraS5mYWN0Y2VudGVyLm9yZy9tZWVya2F0LXJvb3QtY2EuY3J0
 | 
				
			||||||
 | 
					MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5mYWN0Y2VudGVyLm9yZy8wCgYIKoZI
 | 
				
			||||||
 | 
					zj0EAwIDSQAwRgIhALEMHq2ssC9rLXiG8v6NcZetwwxdu3B3LW9s0KeGoNIEAiEA
 | 
				
			||||||
 | 
					skA56tMnhiZe38msyanRyRrAHyBI2fGs6GP3UBrg2P8=
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					V	251108160802Z		1000	unknown	/CN=Meerkat Voting Intermediate CA 1/ST=Some-State/C=IL/O=IDC Herzliya/OU=Meerkat Voting Team
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					unique_subject = no
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					1001
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					1000
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					1000
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,61 @@
 | 
				
			||||||
 | 
					[ ca ]
 | 
				
			||||||
 | 
					default_ca = myca
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ crl_ext ]
 | 
				
			||||||
 | 
					issuerAltName=issuer:copy 
 | 
				
			||||||
 | 
					authorityKeyIdentifier=keyid:always
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ myca ]
 | 
				
			||||||
 | 
					 dir = ./
 | 
				
			||||||
 | 
					 new_certs_dir = $dir
 | 
				
			||||||
 | 
					 unique_subject = no
 | 
				
			||||||
 | 
					 certificate = $dir/root-ca.crt
 | 
				
			||||||
 | 
					 database = $dir/certindex
 | 
				
			||||||
 | 
					 private_key = $dir/root-ca-private-key.pem
 | 
				
			||||||
 | 
					 serial = $dir/certserial
 | 
				
			||||||
 | 
					 default_days = 3650
 | 
				
			||||||
 | 
					 default_md = sha256
 | 
				
			||||||
 | 
					 policy = myca_policy
 | 
				
			||||||
 | 
					 x509_extensions = myca_extensions
 | 
				
			||||||
 | 
					 crlnumber = $dir/crlnumber
 | 
				
			||||||
 | 
					 default_crl_days = 3650
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ myca_policy ]
 | 
				
			||||||
 | 
					 commonName = supplied
 | 
				
			||||||
 | 
					 stateOrProvinceName = optional
 | 
				
			||||||
 | 
					 countryName = optional
 | 
				
			||||||
 | 
					 emailAddress = optional
 | 
				
			||||||
 | 
					 organizationName = supplied
 | 
				
			||||||
 | 
					 organizationalUnitName = optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ myca_extensions ]
 | 
				
			||||||
 | 
					 basicConstraints = critical,CA:TRUE
 | 
				
			||||||
 | 
					 keyUsage = critical,any
 | 
				
			||||||
 | 
					 subjectKeyIdentifier = hash
 | 
				
			||||||
 | 
					 authorityKeyIdentifier = keyid:always,issuer
 | 
				
			||||||
 | 
					 keyUsage = digitalSignature,keyEncipherment,cRLSign,keyCertSign
 | 
				
			||||||
 | 
					 extendedKeyUsage = serverAuth
 | 
				
			||||||
 | 
					 crlDistributionPoints = @crl_section
 | 
				
			||||||
 | 
					 subjectAltName  = @alt_names
 | 
				
			||||||
 | 
					 authorityInfoAccess = @ocsp_section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ v3_ca ]
 | 
				
			||||||
 | 
					 basicConstraints = critical,CA:TRUE,pathlen:0
 | 
				
			||||||
 | 
					 keyUsage = critical,any
 | 
				
			||||||
 | 
					 subjectKeyIdentifier = hash
 | 
				
			||||||
 | 
					 authorityKeyIdentifier = keyid:always,issuer
 | 
				
			||||||
 | 
					 keyUsage = digitalSignature,keyEncipherment,cRLSign,keyCertSign
 | 
				
			||||||
 | 
					 extendedKeyUsage = serverAuth
 | 
				
			||||||
 | 
					 crlDistributionPoints = @crl_section
 | 
				
			||||||
 | 
					 subjectAltName  = @alt_names
 | 
				
			||||||
 | 
					 authorityInfoAccess = @ocsp_section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [alt_names]
 | 
				
			||||||
 | 
					 DNS.0 = Meerkat Voting Intermediate CA 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [crl_section]
 | 
				
			||||||
 | 
					 URI.0 = http://crl.factcenter.org/meerkat-root-ca.crl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 [ocsp_section]
 | 
				
			||||||
 | 
					 caIssuers;URI.0 = http://pki.factcenter.org/meerkat-root-ca.crt
 | 
				
			||||||
 | 
					 OCSP;URI.0 = http://ocsp.factcenter.org/
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					-----BEGIN EC PRIVATE KEY-----
 | 
				
			||||||
 | 
					Proc-Type: 4,ENCRYPTED
 | 
				
			||||||
 | 
					DEK-Info: AES-256-CBC,B8CA131346FD6C9568A6C80935F2AF14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					8q1seEln39/tQTo5KqN+qNRhd0fQ0oC71dYpfTHsP0NlNmjMtwKo2niFwzjxnSyP
 | 
				
			||||||
 | 
					vpJjGzUlnq30ucbeJA7CDm/1cmYAU5gGQ7gldgpi2TQVS+EBjqi/Y5P9AlrgLv6K
 | 
				
			||||||
 | 
					tKe4AvkqQcpi4ZvlUL9xmNaM9jEH4syopR9YClEMfa8=
 | 
				
			||||||
 | 
					-----END EC PRIVATE KEY-----
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					-----BEGIN EC PRIVATE KEY-----
 | 
				
			||||||
 | 
					MHQCAQEEIEi9y6pSKu1kDZcIfQQAnojl1iFxm32W0DVCp2P6HRrkoAcGBSuBBAAK
 | 
				
			||||||
 | 
					oUQDQgAEoijIYF12bpA0tcjyQnWZGQ4lzdBGR+hK/5al/M+zFgFwvWHoWf6yJsSB
 | 
				
			||||||
 | 
					ymviB5yUaH+cE+/3LXlGbpRzYKLBYQ==
 | 
				
			||||||
 | 
					-----END EC PRIVATE KEY-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIICpTCCAkygAwIBAgIJAJoVb07aGgNaMAoGCCqGSM49BAMCMIGwMQswCQYDVQQG
 | 
				
			||||||
 | 
					EwJJTDETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwISGVyemxpeWExFDAS
 | 
				
			||||||
 | 
					BgNVBAoMC0lEQyBIZXJsaXlhMR8wHQYDVQQLDBZNZWVya2F0IFZvdGluZyBQcm9q
 | 
				
			||||||
 | 
					ZWN0MRgwFgYDVQQDDA9UZXN0aW5nIFJvb3QgQ0ExKDAmBgkqhkiG9w0BCQEWGXRl
 | 
				
			||||||
 | 
					c3RpbmctY2FAZmFjdGNlbnRlci5vcmcwHhcNMTUxMTExMTUzODE4WhcNMjUxMTA4
 | 
				
			||||||
 | 
					MTUzODE4WjCBsDELMAkGA1UEBhMCSUwxEzARBgNVBAgMClNvbWUtU3RhdGUxETAP
 | 
				
			||||||
 | 
					BgNVBAcMCEhlcnpsaXlhMRQwEgYDVQQKDAtJREMgSGVybGl5YTEfMB0GA1UECwwW
 | 
				
			||||||
 | 
					TWVlcmthdCBWb3RpbmcgUHJvamVjdDEYMBYGA1UEAwwPVGVzdGluZyBSb290IENB
 | 
				
			||||||
 | 
					MSgwJgYJKoZIhvcNAQkBFhl0ZXN0aW5nLWNhQGZhY3RjZW50ZXIub3JnMFYwEAYH
 | 
				
			||||||
 | 
					KoZIzj0CAQYFK4EEAAoDQgAEoijIYF12bpA0tcjyQnWZGQ4lzdBGR+hK/5al/M+z
 | 
				
			||||||
 | 
					FgFwvWHoWf6yJsSBymviB5yUaH+cE+/3LXlGbpRzYKLBYaNQME4wHQYDVR0OBBYE
 | 
				
			||||||
 | 
					FIkP0vV8uZfgD0IGguxhefc4/LWiMB8GA1UdIwQYMBaAFIkP0vV8uZfgD0IGguxh
 | 
				
			||||||
 | 
					efc4/LWiMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgNftHrW30Git8
 | 
				
			||||||
 | 
					VFQKyMCkasauSpEHpAGdcRAhRHqUQMUCIDxw++trz/Iv8818xVB1ARr9EQAmH0aC
 | 
				
			||||||
 | 
					7MHETGuiBC7L
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					-----BEGIN EC PARAMETERS-----
 | 
				
			||||||
 | 
					BgUrgQQACg==
 | 
				
			||||||
 | 
					-----END EC PARAMETERS-----
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue