Giter Site home page Giter Site logo

c2c-common's Introduction

Java Implementation of ITS Intelligent Transport Systems (ITS) Security header and certificate formats

This is a library used to generate data structures from the ETSI TS 103 097 v1.3.1, ETSI TS 102 941 v1.3.1 (EU) and IEEE 1609.2 2016 (With 1609.2a 2017 Amendment) (US) specification.

License

The software is released under AGPL, LICENSE.txt for more details. In order to get the software under a different licensing agreement please contact p.vendil (at) cgi.com

Changelog

2.0.0-Beta5

  • Refactored certificate store from a Map<HashedId8,Certificate> to a more abstract CertStore.

2.0.0-Beta4

  • Migrated build system to gradle

  • Fixed bug #8 where negative COER Integers was wrongly encoded

  • Fixed byg #9 where Time64 was encoded in milliseconds instead of specified microseconds

  • Improved decryptAndVerify result to add signer info and symmetric key for ETSA TS 102941 Messages.

2.0.0-Beta3

  • Updated support to Etsi TS 102 941 v 1.3.1

2.0.0-Beta2

  • Support for generating CA Messages according to Etsi TS 102 941 v 1.2.1

  • Fix for bad encoding of Time64 data structures (it used nano seconds instead of milliseconds).

  • Changed compile target to JDK 8.

  • Some refactoring.

2.0.0-Beta1

  • Updated IEEE 1609.2 support to 2016 with 1609.2a 2017 amendment.

  • Added support to generate new ITS ETSI TS 103 097 V1.3.1 structures based on 1609.2a 2017

  • Added test vector test of cryptographic algorithms from IEEE 1609.2a 2017

  • Removed old ITS ETSI TS 103 097 V1.2.1 code and generators

  • Fixed problem with COERBoolean

0.9.8

  • Added support for ETSI TS 103 097 V1.2.1 (Version 2 certificate and SecureMessages), V2 Certificates and SecureMessages have been interoperability tested with ETSI test tool from ts_10309603v010201p0 package. (Tests was done to verify generated messages and generation and parsing of certificates).

  • Added utility methods to retrieve java.security variant of verification public key from certificates (common API for both US and EU standard)

0.9.7

  • Added support for IEEE 1609.2 certificate (US standard)

0.9.6

  • Improved automatic build of project.

0.9.5

  • Interoperability testing of all aspects except encryption.

  • Bug-fixes on signature generation where trailer field signature type wasn’t included in the digest calculation.

0.9.0

  • Ecies Encryption scheme support in DefaultCryptoManager

  • Restructured the behaviour of CryptoManager verifySecuredMessage to throw InvalidITSSignatureException instead of returning a boolean

EU Standard ETSI TS 103 097 V1.3.1

It supports generation of the following data structures will all related substructures:

  • Root CA Certificate

  • Enrollment CA Certificate

  • Authorization CA Certificate

  • Enrollment Credential Certificate

  • Authorization Ticket

  • Trust List Manager Certificate

  • Secure Messages (CAM and DENM) and others

See Javadoc and examples below for more detailed information.

Example Code

Full example code can be seen in src/test/java/org/certificateservices/custom/c2x/demo it contains demo of both ETSI (EU) and IEEE (US) standards.

Before doing anything else you need to initialize a CryptoManager used for all cryptographic operations.

    	//Create a crypto manager in charge of communicating with underlying cryptographic components
	    CryptoManager cryptoManager = new DefaultCryptoManager();
	    // Initialize the crypto manager to use soft keys using the bouncy castle cryptographic provider.
	    cryptoManager.setupAndConnect(new DefaultCryptoManagerParams("BC"));

Root CA

Example code on how to generate Root a CA, use the AuthorityCertGenerator:

	    // Create an authority certificate generator and initialize it with the crypto manager.
	    ETSIAuthorityCertGenerator authorityCertGenerator = new ETSIAuthorityCertGenerator(cryptoManager);

	    // Generate a reference to the Root CA Keys
	    KeyPair rootCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    KeyPair rootCAEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    ValidityPeriod rootCAValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 45);
	    List<Integer> countries = new ArrayList<Integer>();
	    countries.add(SWEDEN);
		GeographicRegion region = GeographicRegion.generateRegionForCountrys(countries);

	    // Generate the root CA Certificate, without any encryption keys or geographic region.
	    EtsiTs103097Certificate rootCACertificate = authorityCertGenerator.genRootCA("testrootca.test.com", // caName
	    		rootCAValidityPeriod, //ValidityPeriod
	    		region, //GeographicRegion
                3, // minChainDepth
                -1, // chainDepthRange
				Hex.decode("0138"), // cTLServiceSpecificPermissions, 2 octets
	    		SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
	    		rootCASigningKeys.getPublic(), // signPublicKey
	    		rootCASigningKeys.getPrivate(), // signPrivateKey
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,  // encPublicKeyAlgorithm
	    		rootCAEncryptionKeys.getPublic()); // encPublicKey
		// There also exists a more general root ca generation method giving more flexibility in parameters.

Enrollment CA

To generate an Enrollment CA:

	    // Generate a reference to the Enrollment CA Keys
	    KeyPair enrollmentCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    KeyPair enrollmentCAEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    ValidityPeriod enrollmentCAValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 37);

	    // Generate a reference to the Enrollment CA Signing Keys
		EtsiTs103097Certificate enrollmentCACertificate =authorityCertGenerator.genEnrollmentCA("testea.test.com", // CA Name
				enrollmentCAValidityPeriod,
				region,  //GeographicRegion
				new SubjectAssurance(1,3), // subject assurance (optional)
                SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
                enrollmentCASigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
				rootCACertificate, // signerCertificate
				rootCASigningKeys.getPublic(), // signCertificatePublicKey, must be specified separately to support implicit certificates.
				rootCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,  // encPublicKeyAlgorithm
	    		enrollmentCAEncryptionKeys.getPublic() // encryption public key
	    		);

Authority CA

To generate an Authority CA:

	    // Generate a reference to the Authorization CA Keys
	    KeyPair authorityCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    KeyPair authorityCAEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    ValidityPeriod authorityCAValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 15);

	    // Generate a reference to the Authorization CA Signing Keys
		EtsiTs103097Certificate authorityCACertificate = authorityCertGenerator.genAuthorizationCA(
				"testaa.test.com", // CA Name
	    		authorityCAValidityPeriod,
				region,  //GeographicRegion
				new SubjectAssurance(1,3), // subject assurance (optional)
                SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
                authorityCASigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
				rootCACertificate, // signerCertificate
				rootCASigningKeys.getPublic(), // signCertificatePublicKey,
				rootCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,  // encPublicKeyAlgorithm
	    		authorityCAEncryptionKeys.getPublic() // encryption public key
	    		);

Enrollment Credential

To create an Enrollment Credential use the EnrollmentCredentialCertGenerator.

	    // First we create a Enrollment Credential Cert Generator using the newly created Enrollment CA.
		ETSIEnrollmentCredentialGenerator enrollmentCredentialCertGenerator = new ETSIEnrollmentCredentialGenerator(cryptoManager);
	    // Next we generate keys for an enrollment credential.
	    KeyPair enrollmentCredentialSigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    // Next we generate keys for an enrollment credential.
	    KeyPair enrollmentCredentialEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    ValidityPeriod enrollCertValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 35);

	    // Then use the following command to generate a enrollment credential
		EtsiTs103097Certificate enrollmentCredential = enrollmentCredentialCertGenerator.genEnrollCredential(
				"0102030405060708", // unique identifier name
	    		enrollCertValidityPeriod,
	    		region,
	    		Hex.decode("01C0"), //SSP data set in SecuredCertificateRequestService appPermission, two byte, for example: 0x01C0
	    		3, // assuranceLevel
				7, // confidenceLevel
	    		SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
	    		enrollmentCredentialSigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
	    		enrollmentCACertificate, // signerCertificate
	    		enrollmentCASigningKeys.getPublic(), // signCertificatePublicKey,
	    		enrollmentCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256, // encPublicKeyAlgorithm
	    		enrollmentCredentialEncryptionKeys.getPublic() // encryption public key
	    		);

	    // There also exists a more general method with flexible app permissions.

Authorization Ticket

To create an Authorization Ticket l use the AuthorizationTicketCertGenerator.

	    // Authorization tickets are created by the ETSIAuthorizationTicketGenerator
		ETSIAuthorizationTicketGenerator authorizationCertGenerator = new ETSIAuthorizationTicketGenerator(cryptoManager);

	    // Next we generate keys for an authorization certificate.
	    KeyPair authorizationTokenSigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    // Next we generate keys for an authorization certificate.
	    KeyPair authorizationTicketEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    ValidityPeriod authorizationCertValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 35);

		PsidSsp[] appPermissions = new PsidSsp[1];
		appPermissions[0] = new PsidSsp(new Psid(6), null); // Insert proper app permissions here.

	    // Generate a certificate as an explicit certificate.
		EtsiTs103097Certificate authorizationCert = authorizationCertGenerator.genAuthorizationTicket(
	    		authorizationCertValidityPeriod, // Validity Period
	    		region, // region,
				new SubjectAssurance(1,3), // Subject Assurance, optional
	    		appPermissions,
	    		SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
				authorizationTokenSigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
	    		authorityCACertificate, // signerCertificate
	    		authorityCASigningKeys.getPublic(), // signCertificatePublicKey,
	    		authorityCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256, // encPublicKeyAlgorithm
				authorizationTicketEncryptionKeys.getPublic() // encryption public key
	    		);

Trust List Manager Certificate

To create a trust list manager certificate.

		// Generate a reference to the Root CA Keys
		KeyPair tlmSigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
		KeyPair tlmEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

		ValidityPeriod tlmValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 45);
		// Generate the root CA Certificate, without any encryption keys or geographic region.
		EtsiTs103097Certificate trustListManagerCertificate = authorityCertGenerator.genTrustListManagerCert(
				"testtlm.test.com", // name
				rootCAValidityPeriod, //ValidityPeriod
				region, //GeographicRegion, optional
				Hex.decode("01C8"), // cTLServiceSpecificPermissions, 2 octets
				SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
				rootCASigningKeys.getPublic(), // signPublicKey
				rootCASigningKeys.getPrivate() // signPrivateKey
				 );
		// There also exists a more general root ca generation method giving more flexibility in parameters.

Secured Messages

To create Secured Messages such as CAM or DENM use the SecuredMessageGenerator.

	    	    // EtsiTs103097Data are created by the Secure Message Generator
        		ETSISecuredDataGenerator securedMessageGenerator = new ETSISecuredDataGenerator(ETSISecuredDataGenerator.DEFAULT_VERSION, cryptoManager, HashAlgorithm.sha256, SignatureChoices.ecdsaNistP256Signature);

        		// To generate a Signed CA Message it is possible to use
        		List<HashedId3> hashedId3s = new ArrayList<HashedId3>();
        		hashedId3s.add(new HashedId3(cryptoManager.digest(rootCACertificate.getEncoded(),HashAlgorithm.sha256)));
        		hashedId3s.add(new HashedId3(cryptoManager.digest(enrollmentCACertificate.getEncoded(),HashAlgorithm.sha256)));
        		SequenceOfHashedId3 inlineP2pcdRequest = new SequenceOfHashedId3(hashedId3s);

        		byte[] cAMessageData = Hex.decode("SomeCAMessage");
        		EtsiTs103097DataSigned cAMessage = securedMessageGenerator.genCAMessage(new Time64(new Date()), // generationTime
        				inlineP2pcdRequest, //  InlineP2pcdRequest (Required)
        				rootCACertificate, // requestedCertificate
        				cAMessageData, // inner opaque CA message data
        				SecuredDataGenerator.SignerIdentifierType.SIGNER_CERTIFICATE, // signerIdentifierType
        				authorizationCert, // signerCertificate
        				authorizationTokenSigningKeys.getPrivate()); // signerPrivateKey


        		// To generate a Signed DEN Message
        		byte[] dENMessageData = Hex.decode("SomeDENMessage");
        		EtsiTs103097DataSigned dENMessage = securedMessageGenerator.genDENMessage(
        				new Time64(new Date()), // generationTime
        				new ThreeDLocation(1,2,3), // generationLocation
        				dENMessageData, // inner opaque DEN message data
        				authorizationCert, // signerCertificate
        				authorizationTokenSigningKeys.getPrivate()); // signerPrivateKey

        		// The securedMessageGenerator also have methods to generate more general EtsiTs103097Data profiles such as
        		// EtsiTs103097DataSigned, EtsiTs103097DataSignedExternalPayload, EtsiTs103097DataEncrypted and
        		// EtsiTs103097DataSignedAndEncrypted.

        	    // It is then possible to create a signed message with the following code
        	      // First generate a Header with
        	    HeaderInfo hi = securedMessageGenerator.genHeaderInfo(
        	    		123L, // psid Required,
        	    		null, // generationTime Optional
        	    		null, // expiryTime Optional
        	    		null, // generationLocation Optional
        	    		null, // p2pcdLearningRequest Optional
        	    		null, // cracaid Optional
        	    		null, // crlSeries Optional
        	    		null, // encType Type of encryption when encrypting a message with a encryption key references in a signed message instead of a certificate. Optional
        	    		null, // encryptionKey Optional
        				null, // inlineP2pcdRequest Optional
        		null // requestedCertificate Optional
        	    		);

        	    // This method can be used to sign the data
        		EtsiTs103097DataSigned signedData = securedMessageGenerator.genEtsiTs103097DataSigned(hi,
        	    		"TestData".getBytes(), // The actual payload message to sign.
        	    		SecuredDataGenerator.SignerIdentifierType.HASH_ONLY, // One of  HASH_ONLY, SIGNER_CERTIFICATE, CERT_CHAIN indicating reference data of the signer to include in the message
        	    		new EtsiTs103097Certificate[] {authorizationCert,authorityCACertificate, rootCACertificate}, // The chain is required even though it isn't included in
        	    		  // the message if eventual implicit certificates need to have it's public key reconstructed.
        	    		authorizationTokenSigningKeys.getPrivate()); // Signing Key
        		// It is also possible to generate a EtsiTs103097DataSignedExternalPayload with the genEtsiTs103097DataSignedExternalPayload()
        		// method.

        	    // The message can be encrypted with the method
        	      // First construct a list of recipient which have the public key specified either as a symmetric key, certificate or in header of signed data
        	      // In this example we will use certificate as reciever, see package org.certificateservices.custom.c2x.ieee1609dot2.generator.recipient for more details.
        		EtsiTs103097DataEncrypted encryptedData = securedMessageGenerator.genEtsiTs103097DataEncrypted(BasePublicEncryptionKeyChoices.ecdsaNistP256,
        	    		  signedData.getEncoded(), new Recipient[] {new CertificateRecipient(enrollmentCredential)});

        	    // It is also possible to sign and encrypt in one go.
        		EtsiTs103097DataEncrypted encryptedAndSignedMessage = securedMessageGenerator.genEtsiTs103097DataSignedAndEncrypted(hi,
        	    		"TestData2".getBytes(),
        	    		SecuredDataGenerator.SignerIdentifierType.HASH_ONLY,
        	    		new EtsiTs103097Certificate[] {authorizationCert,authorityCACertificate, rootCACertificate},
        				authorizationTokenSigningKeys.getPrivate(), // Important to use the reconstructed private key for implicit certificates
        	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,
        	    		new Recipient[] {new CertificateRecipient(enrollmentCredential)});

        	    // To decrypt and verify a signed message it is possible to use the following
        	      // First build a truststore of trust anchors (root CA certificate or equivalent)
        	    Map<HashedId8, Certificate> trustStore = securedMessageGenerator.buildCertStore(new EtsiTs103097Certificate[] {rootCACertificate});
        	      // Second build a store of known certificate that might be referenced in the message.
        	    Map<HashedId8, Certificate> certStore = securedMessageGenerator.buildCertStore(new EtsiTs103097Certificate[] {authorizationCert, authorityCACertificate});
        	      // To decrypt build a reciever store of known decryption keys and related receiver info, this can be certificate, signed message containing encryption key
        	      // in header, symmetric key or pre shared key.
        	    Map<HashedId8, Receiver> recieverStore = securedMessageGenerator.buildRecieverStore(new Receiver[] { new CertificateReciever(enrollmentCredentialEncryptionKeys.getPrivate(), enrollmentCredential)});
        		  // Finally perform the decryption and verification of siganture with.
        		DecryptAndVerifyResult decryptAndVerifyResult = securedMessageGenerator.decryptAndVerifySignedData(encryptedAndSignedMessage.getEncoded(),
        	    		certStore,
        	    		trustStore,
        	    		recieverStore,
        	    		true, //requiredSignature true if message must be signed otherwise a IllegalArgument is throwm
        	    		true //requireEncryption true if message must be encrypted otherwise a IllegalArgument is throwm
        	    		);
        		   // The decryptAndVerifyResult contains the inner opaque data, the related header info and signer identifier
        		   // if related message was signed.

        	      // It is also possible to use the methods decryptData or verifySignedData (or verifyReferencedSignedData) for alternative methods to verify and decrypt messages.

To Encode and Decode Certificates and Secured Messages

	    // To encode a certificate to a byte array use the following method
	    byte[] certificateData = authorizationCert.getEncoded();

	    // To decode certificate data use the following constructor
	    EtsiTs103097Certificate decodedCertificate = new EtsiTs103097Certificate(certificateData);

	    // To decode message data use the following constructor.
	    EtsiTs103097Data decodedMessage = new EtsiTs103097Data(messageData);
	    // If the message profile is known there also exists EtsiTs103097DataSigned, EtsiTs103097DataSignedExternalPayload,
	    // EtsiTs103097DataEncrypted classes that performs validation according to each profile.

EU Standard ETSI TS 102 941 V1.3.1

It supports generation of the following data structures will all related substructures:

  • Enrol Request/Response Message

  • Authorization Request/Response Message

  • Authorization Validation Request/Response Message

  • CRL and CTL Messages

  • CA Request Message (With Rekey)

See Javadoc and examples below for more detailed information.

Example Code

Full example code can be seen in src/test/java/org/certificateservices/custom/c2x/demo. The example code assumes you have access to a generated PKI according to ETSI TS 103 097 standard.

Before generating any CA Message create a CA Message generator with:

        // Create a ETSITS102941MessagesCaGenerator generator
        messagesCaGenerator = new ETSITS102941MessagesCaGenerator(Ieee1609Dot2Data.DEFAULT_VERSION,
                cryptoManager, // The initialized crypto manager to use.
                HashAlgorithm.sha256, // digest algorithm to use.
                Signature.SignatureChoices.ecdsaNistP256Signature,  // define which signature scheme to use.
                false); // If EC points should be represented as uncompressed.

EnrolRequestMessage

To create an EnrolRequestMessage use the following code.

        // First create the InnerEcRequest object
        InnerEcRequest initialInnerEcRequest = genDummyInnerEcRequest(enrolCredSignKeys.getPublic());
        EtsiTs103097DataEncryptedUnicast initialEnrolRequestMessage = messagesCaGenerator.genInitialEnrolmentRequestMessage(
                new Time64(new Date()), // generation Time
                initialInnerEcRequest,
                enrolCredSignKeys.getPublic(),enrolCredSignKeys.getPrivate(), // The key pair used in the enrolment credential used for self signed PoP
                enrolmentCACert); // The EA certificate to encrypt message to.

        // All messages can be encoded to byte[] using
        byte[] encodedMessage = initialEnrolRequestMessage.getEncoded();

        // To parse and encoded message create a new instance of related EtsiTs103097Data profile.
        EtsiTs103097DataEncryptedUnicast decodedMessage = new EtsiTs103097DataEncryptedUnicast(encodedMessage);

        // To Create an rekey EnrolRequestMessage use the following code.

        // Use a separate method when performing rekey that contains signature of previous message.
        InnerEcRequest reKeyInnerEcRequest = genDummyInnerEcRequest(enrolCredReSignKeys.getPublic());
        EtsiTs103097DataEncryptedUnicast rekeyEnrolRequestMessage = messagesCaGenerator.genRekeyEnrolmentRequestMessage(
                new Time64(new Date()), // generation Time
                reKeyInnerEcRequest, // Inner EC Request containing PublicKeys with new keys.
                enrollmentCredCertChain, // The certificate chain of the current (old) enrolment credential.
                enrolCredSignKeys.getPrivate(), // Private key if current (old) enrolment credential.
                enrolCredReSignKeys.getPublic(),enrolCredReSignKeys.getPrivate(), // The key pair used in the enrolment credential used for self signed PoP
                enrolmentCACert); // The EA certificate to encrypt message to.

To verify a EnrolRequestMessage use:

        // First build a certificate store and a trust store to verify signature.
        // These can be null if only initial messages are used.
        Map<HashedId8, Certificate> enrolCredCertStore = messagesCaGenerator.buildCertStore(enrollmentCredCertChain);
        Map<HashedId8, Certificate> trustStore = messagesCaGenerator.buildCertStore(new EtsiTs103097Certificate[]{rootCACert});

        // Then create a receiver store to decrypt the message
        Map<HashedId8, Receiver> enrolCAReceipients = messagesCaGenerator.buildRecieverStore(new Receiver[] {new CertificateReciever(enrolCAEncKeys.getPrivate(),enrolmentCACert)});
        // Then decrypt and verify with:
        // Important: this method only verifies the signature, it does not validate header information.
        RequestVerifyResult<InnerEcRequest> enrolmentRequestResult = messagesCaGenerator.decryptAndVerifyEnrolmentRequestMessage(rekeyEnrolRequestMessage,enrolCredCertStore,trustStore,enrolCAReceipients);
        // The verify result for enrolment request returns a special value object containing both inner message and
        // requestHash used in response.

        // The result object of all verify message method contains the following information:
        enrolmentRequestResult.getSignerIdentifier(); // The identifier of the signer
        enrolmentRequestResult.getHeaderInfo(); // The header information of the signer of the message
        enrolmentRequestResult.getValue(); // The inner message that was signed and or encrypted.
        enrolmentRequestResult.getSecretKey(); // The symmetrical key used in Ecies request operations and is set when verifying all
        // request messages. The secret key should usually be used to encrypt the response back to the requester.

EnrolResponseMessage

To generate and verify EnrolResponseMessage

        // First generate a InnerECResponse
        InnerEcResponse innerEcResponse = new InnerEcResponse(enrolmentRequestResult.getRequestHash(), EnrollmentResponseCode.ok,enrolmentCredCert);
        // Then generate the EnrolmentResponseMessage with:
        EtsiTs103097DataEncryptedUnicast enrolResponseMessage = messagesCaGenerator.genEnrolmentResponseMessage(
                new Time64(new Date()), // generation Time
                innerEcResponse,
                enrollmentCAChain, // Chain of EA used to sign message
                enrolCASignKeys.getPrivate(),
                SymmAlgorithm.aes128Ccm, // Encryption algorithm used
                enrolmentRequestResult.getSecretKey()); // Use symmetric key from the verification result when verifying the request.

        // To verify EnrolResponseMessage use:
        // Build certstore
        Map<HashedId8, Certificate> enrolCACertStore = messagesCaGenerator.buildCertStore(enrollmentCAChain);

        // Build reciever store containing the symmetric key used in the request.
        Map<HashedId8, Receiver> enrolCredSharedKeyReceivers = messagesCaGenerator.buildRecieverStore(new Receiver[] {new PreSharedKeyReceiver(enrolmentRequestResult.getSecretKey())});
        VerifyResult<InnerEcResponse> enrolmentResponseResult = messagesCaGenerator.decryptAndVerifyEnrolmentResponseMessage(
                enrolResponseMessage,
                enrolCACertStore, // Certificate chain if EA CA
                trustStore,
                enrolCredSharedKeyReceivers
        );

AuthorizationRequestMessage

To generate and verify AuthorizationRequestMessage

        // To generate an AuthorizationRequestMessage it is possible to generate
        // the message with and without POP and privacy set. This example generates
        // message with POP and privacy.

        // First generate a PublicKeys, hmacKey and SharedAtRequest structures
        PublicKeys publicKeys = messagesCaGenerator.genPublicKeys(signAlg,authTicketSignKeys.getPublic(),SymmAlgorithm.aes128Ccm,encAlg, authTicketEncKeys.getPublic());
        byte[] hmacKey = genHmacKey();
        SharedAtRequest sharedAtRequest = genDummySharedAtRequest(publicKeys, hmacKey);

        EtsiTs103097DataEncryptedUnicast authRequestMessage = messagesCaGenerator.genAuthorizationRequestMessage(
                new Time64(new Date()), // generation Time
                publicKeys,
                hmacKey,
                sharedAtRequest,
                enrollmentCredCertChain, // Certificate chain of enrolment credential to sign outer message to AA
                enrolCredSignKeys.getPrivate(), // Private key used to sign message.
                authTicketSignKeys.getPublic(), //The public key of the auth ticket, used to create POP, null if no POP should be generated.
                authTicketSignKeys.getPrivate(), // The private key of the auth ticket, used to create POP, null if no POP should be generated.
                authorizationCACert, // The AA certificate to encrypt outer message to.
                enrolmentCACert, // Encrypt inner ecSignature with given certificate, required if withPrivacy is true.
                true // Encrypt the inner ecSignature message sent to EA
        );

         // To verify an AuthorizationRequest use the following code.

         // Build a recipient store for Authorization Authority
        Map<HashedId8, Receiver> authorizationCAReceipients = messagesCaGenerator.buildRecieverStore(new Receiver[] {new CertificateReciever(authorizationCAEncKeys.getPrivate(),authorizationCACert)});

        // To decrypt the message and verify the external POP signature (not the inner eCSignature signed for EA CA).
        RequestVerifyResult<InnerAtRequest> authRequestResult = messagesCaGenerator.decryptAndVerifyAuthorizationRequestMessage(authRequestMessage,
                 true, // Expect AuthorizationRequestPOP content
                 authorizationCAReceipients); // Receivers able to decrypt the message
        // The AuthorizationRequestData contains the innerAtRequest and calculated requestHash
        InnerAtRequest innerAtRequest = authRequestResult.getValue();
        // There exists another method to decrypt (if privacy is used) and verify inner ecSignature with:
        VerifyResult<EcSignature> ecSignatureVerifyResult = messagesCaGenerator.decryptAndVerifyECSignature(innerAtRequest.getEcSignature(),
                innerAtRequest.getSharedAtRequest(),
                true,
                enrolCredCertStore, // Certificate store to verify the signing enrollment credential
                trustStore,
                enrolCAReceipients); // the EA certificate used to decrypt the inner message.

        // The verified and decrypted (if withPrivacy) eCSignature is retrived with
        EcSignature ecSignature = ecSignatureVerifyResult.getValue();

AuthorizationResponseMessage

To generate and verify AuthorizationResponseMessage

        // First create innerAtResponse
        InnerAtResponse innerAtResponse = new InnerAtResponse(authRequestResult.getRequestHash(),
                AuthorizationResponseCode.ok,
                authTicketCert);
        EtsiTs103097DataEncryptedUnicast authResponseMessage = messagesCaGenerator.genAuthorizationResponseMessage(
                new Time64(new Date()), // generation Time
                innerAtResponse,
                authorizationCAChain, // The AA certificate chain signing the message
                authorizationCASignKeys.getPrivate(),
                SymmAlgorithm.aes128Ccm, // Encryption algorithm used.
                authRequestResult.getSecretKey()); // The symmetric key generated in the request.


        // To verify AuthorizationResponse use:

        // Build reciever store containing the symmetric key used in the request.
        Map<HashedId8, Receiver> authTicketSharedKeyReceivers = messagesCaGenerator.buildRecieverStore(new Receiver[] {new PreSharedKeyReceiver(authRequestResult.getSecretKey())});
        Map<HashedId8, Certificate> authCACertStore = messagesCaGenerator.buildCertStore(authorizationCAChain);
        VerifyResult<InnerAtResponse> authResponseResult = messagesCaGenerator.decryptAndVerifyAuthorizationResponseMessage(authResponseMessage,
                authCACertStore, // certificate store containing certificates for auth cert.
                trustStore,
                authTicketSharedKeyReceivers);

AuthorizationValidationRequestMessage

To generate and verify AuthorizationValidationRequestMessage

        // The authorization validation request is sent between AA and EA and should
        // contain the SharedATRequest and ecSignature structures.
        AuthorizationValidationRequest authorizationValidationRequest = new AuthorizationValidationRequest(
                innerAtRequest.getSharedAtRequest(),innerAtRequest.getEcSignature());

        EtsiTs103097DataEncryptedUnicast authorizationValidationRequestMessage = messagesCaGenerator.genAuthorizationValidationRequest(
                new Time64(new Date()), // generation Time
                authorizationValidationRequest,
                authorizationCAChain,// The AA certificate chain to generate the signature.
                authorizationCASignKeys.getPrivate(), // The AA signing keys
                enrolmentCACert); // The EA certificate to encrypt data to.


         // To verify an Authorization Validation Request

        RequestVerifyResult<AuthorizationValidationRequest> authorizationValidationRequestVerifyResult = messagesCaGenerator.decryptAndVerifyAuthorizationValidationRequestMessage(
                 authorizationValidationRequestMessage,
                 authCACertStore, // certificate store containing certificates for auth cert.
                 trustStore,
                 enrolCAReceipients);

AuthorizationValidationResponseMessage

To generate and verify AuthorizationValidationResponseMessage

         // First generate inner authorizationValidationResponse object
        AuthorizationValidationResponse authorizationValidationResponse = new AuthorizationValidationResponse(
                authorizationValidationRequestVerifyResult.getRequestHash(),
                AuthorizationValidationResponseCode.ok,
                genDummyConfirmedSubjectAttributes());
        EtsiTs103097DataEncryptedUnicast authorizationValidationResponseMessage = messagesCaGenerator.genAuthorizationValidationResponseMessage(
                new Time64(new Date()), // generation Time
                authorizationValidationResponse,
                enrollmentCAChain, // EA signing chain
                enrolCASignKeys.getPrivate(), // EA signing private key
                SymmAlgorithm.aes128Ccm, // Encryption algorithm used.
                authorizationValidationRequestVerifyResult.getSecretKey() // The symmetric key generated in the request.
                );


        // To verify an Authorization Validation Response

        Map<HashedId8, Receiver> authValidationSharedKeyReceivers = messagesCaGenerator.buildRecieverStore(new Receiver[] {new PreSharedKeyReceiver(authorizationValidationRequestVerifyResult.getSecretKey())});
        VerifyResult<AuthorizationValidationResponse> authorizationValidationResponseVerifyResult = messagesCaGenerator.decryptAndVerifyAuthorizationValidationResponseMessage(
                authorizationValidationResponseMessage,
                enrolCACertStore,
                trustStore,
                authValidationSharedKeyReceivers);

Generate CTL and CRL messages

To generate and verify CTL and CRL messages use:

        // The messages CertificateRevocationListMessage, TlmCertificateTrustListMessage and RcaCertificateTrustListMessage
        // are all generated using very similar methods. Only CertificateRevocationListMessage is shown here.

        // First generate to be signed data
        ToBeSignedCrl toBeSignedCrl = genDummyCRLToBeSignedData();
        EtsiTs103097DataSigned certificateRevocationListMessage = messagesCaGenerator.genCertificateRevocationListMessage(
                new Time64(new Date()), // signing generation time
                toBeSignedCrl,
                new EtsiTs103097Certificate[]{rootCACert}, // certificate chain of signer
                rootCAKeys.getPrivate()); // Private key of signer

        // To verify CTL and CRL messages
        Map<HashedId8, Certificate> crlTrustStore = new HashMap<>(); // Only root ca needed from truststore in this case.
        VerifyResult<ToBeSignedCrl> crlVerifyResult = messagesCaGenerator.verifyCertificateRevocationListMessage(
                certificateRevocationListMessage,
                crlTrustStore,
                trustStore
        );

CARequestMessage and Rekey

To generate and verify inital and rekey a CARequestMessage use:

        // First generate inner CaCertificatRequest
        CaCertificateRequest caCertificateRequest = genDummyCaCertificateRequest(authorizationCASignKeys.getPublic());
        // The self sign the message to prove possession.
        EtsiTs103097DataSigned caCertificateRequestMessage = messagesCaGenerator.genCaCertificateRequestMessage(
                new Time64(new Date()), // signing generation time
                caCertificateRequest,
                authorizationCASignKeys.getPublic(), // The CAs signing keys
                authorizationCASignKeys.getPrivate());

       // To verify a CA Request Message

        VerifyResult<CaCertificateRequest> caCertificateRequestVerifyResult = messagesCaGenerator.verifyCACertificateRequestMessage(caCertificateRequestMessage);

        // To generate a Rekey CA Request Message
        CaCertificateRequest caCertificateRekeyRequest = genDummyCaCertificateRequest(authorizationCAReSignKeys.getPublic());
        EtsiTs103097DataSigned caCertificateRekeyRequestMessage =messagesCaGenerator.genCaCertificateRekeyingMessage(
                new Time64(new Date()), // signing generation time,
                caCertificateRekeyRequest,
                authorizationCAChain,
                authorizationCASignKeys.getPrivate(),
                authorizationCAReSignKeys.getPublic(),
                authorizationCAReSignKeys.getPrivate());

        // To Verify a Rekey CA Request Message
        VerifyResult<CaCertificateRequest> caCertificateRekeyRequestVerifyResult = messagesCaGenerator.verifyCACertificateRekeyingMessage(caCertificateRekeyRequestMessage,authCACertStore,trustStore);

US Standard IEEE 1609.2

The implementation supports the following:

  • Encodes using ASN.1 COER

  • Support for both ecdsaNistP256 and ecdsaBrainpoolP256r1 algorithm schemes

  • Generation of RootCA, Enrollment CA (Long Term) and Authorization (Short Term) CA

  • Generation of Enrollment Certificates and Authorization Certificate

  • Support for both explicit and implicit certificate generation

  • Support signing and encryption of SecuredData structures

  • Generation of SecuredCRL structures.

Important: The encryption scheme hasn’t been properly tested for inter-operability yet and might contain wrong ECIES parameters.

Example Code

Full example code can be seen in src/test/java/org/certificateservices/custom/c2x/demo it contains demo of both ITS (EU) and IEEE (US) standards.

Before doing anything else you need to initialize a CryptoManager used for all cryptographic operations.

	    Ieee1609Dot2CryptoManager cryptoManager = new DefaultCryptoManager();
	    // Initialize the crypto manager to use soft keys using the bouncy castle cryptographic provider.
	    cryptoManager.setupAndConnect(new DefaultCryptoManagerParams("BC"));

Root CA

Example code on how to generate Root a CA, use the AuthorityCertGenerator:

	    // Create an authority certificate generator and initialize it with the crypto manager.
	    AuthorityCertGenerator authorityCertGenerator = new AuthorityCertGenerator(cryptoManager);

	    // Generate a reference to the Root CA Keys
	    KeyPair rootCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    KeyPair rootCAEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    CertificateId rootCAId = new CertificateId(new Hostname("Test RootCA"));
	    ValidityPeriod rootCAValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 45);
	    List<Integer> countries = new ArrayList<Integer>();
	    countries.add(SWEDEN);
		GeographicRegion region = GeographicRegion.generateRegionForCountrys(countries);

	    // Generate the root CA Certificate, without any encryption keys or geographic region.
	    Certificate rootCACertificate = authorityCertGenerator.genRootCA(rootCAId, // CertificateId
	    		rootCAValidityPeriod, //ValidityPeriod
	    		region, //GeographicRegion
	    		4, // assuranceLevel
                3, // confidenceLevel
                3, // minChainDepth
                -1, // chainDepthRange
	    		SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
	    		rootCASigningKeys.getPublic(), // signPublicKey
	    		rootCASigningKeys.getPrivate(), // signPrivateKey
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,  // encPublicKeyAlgorithm
	    		rootCAEncryptionKeys.getPublic()); // encPublicKey

Enrollment CA (Long Term)

To generate an Enrollment CA:

	    // Generate a reference to the Enrollment CA Keys
	    KeyPair enrollmentCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    KeyPair enrollmentCAEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    CertificateId enrollmentCAId = new CertificateId(new Hostname("Test Enrollment CA"));
	    ValidityPeriod enrollmentCAValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 37);

		byte[] cracaid = Hex.decode("010203"); // Some cracaid
		PsidSspRange[] subjectPerms = new PsidSspRange[1];
		subjectPerms[0] = new PsidSspRange(new Psid(5), new SspRange(SspRangeChoices.all, null)); // Insert proper subject permissions here.
	    // Generate a reference to the Enrollment CA Signing Keys
	    Certificate enrollmentCACertificate =authorityCertGenerator.genLongTermEnrollmentCA(
	    		CertificateType.explicit, // Implicit or Explicit certificate
	    		enrollmentCAId,// CertificateId
				enrollmentCAValidityPeriod,
				region,  //GeographicRegion
				subjectPerms,
				cracaid,
				99, // CrlSeries
	    		4, // assuranceLevel
                3, // confidenceLevel
                2, // minChainDepth
                0, // chainDepthRange
                SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
                enrollmentCASigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
				rootCACertificate, // signerCertificate
				rootCASigningKeys.getPublic(), // signCertificatePublicKey, must be specified separately to support implicit certificates.
				rootCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,  // encPublicKeyAlgorithm
	    		enrollmentCAEncryptionKeys.getPublic() // encryption public key
	    		);

Authorization CA (Short Term)

To generate an Authorization CA:

        // Generate a reference to the Authorization CA Keys
	    KeyPair authorityCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    KeyPair authorityCAEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    CertificateId authorityCAId = new CertificateId(new Hostname("Test Enrollment CA"));
	    ValidityPeriod authorityCAValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 15);

		cracaid = Hex.decode("040506"); // Some cracaid
		subjectPerms = new PsidSspRange[1];
		subjectPerms[0] = new PsidSspRange(new Psid(6), new SspRange(SspRangeChoices.all, null)); // Insert proper subject permissions here.

	    // Generate a reference to the Authorization CA Signing Keys
	    Certificate authorityCACertificate = authorityCertGenerator.genAuthorizationCA(
	    		CertificateType.explicit, // Implicit or Explicit certificate
	    		authorityCAId,// CertificateId
	    		authorityCAValidityPeriod,
				region,  //GeographicRegion
				subjectPerms,
				cracaid,
				99, // Some CrlSeries
	    		4, // assuranceLevel
                3, // confidenceLevel
                2, // minChainDepth
                0, // chainDepthRange
                SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
                authorityCASigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
				rootCACertificate, // signerCertificate
				rootCASigningKeys.getPublic(), // signCertificatePublicKey,
				rootCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,  // encPublicKeyAlgorithm
	    		authorityCAEncryptionKeys.getPublic() // encryption public key
	    		);

Enrollment Certificate

To create an Enrollment Certificate (explicit in this example) use the EnrollmentCertGenerator.

	    // Now we have the CA hierarchy, the next step is to generate an enrollment credential
	    // First we create a Enrollment Credential Cert Generator using the newly created Enrollment CA.
	    EnrollmentCertGenerator enrollmentCredentialCertGenerator = new EnrollmentCertGenerator(cryptoManager);
	    // Next we generate keys for an enrollment credential.
	    KeyPair enrollmentCredentialSigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);
	    // Next we generate keys for an enrollment credential.
	    KeyPair enrollmentCredentialEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    CertificateId enrollCertId = new CertificateId(Hex.decode("0102030405060708"));
	    ValidityPeriod enrollCertValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 35);

		PsidSspRange[] certRequestPermissions = new PsidSspRange[1];
		certRequestPermissions[0] = new PsidSspRange(new Psid(5), new SspRange(SspRangeChoices.all, null)); // Insert proper subject permissions here.

	    // Then use the following command to generate a enrollment credential
	    Certificate enrollmentCredential = enrollmentCredentialCertGenerator.genEnrollCert(
	    		CertificateType.explicit, // Implicit or Explicit certificate
	    		enrollCertId, // Certificate Id,
	    		enrollCertValidityPeriod,
	    		region,
	    		certRequestPermissions,
	    		cracaid, // insert proper cracaid here.
	    		99, // Some CrlSeries
	    		4,
	    		3,
	    		SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
	    		enrollmentCredentialSigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
	    		enrollmentCACertificate, // signerCertificate
	    		enrollmentCASigningKeys.getPublic(), // signCertificatePublicKey,
	    		enrollmentCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256, // encPublicKeyAlgorithm
	    		enrollmentCredentialEncryptionKeys.getPublic() // encryption public key
	    		);

Authorization Certificate (With implicit certificate)

To create an Authorization Certificate (implicit in this example) use the AuthorizationCertGenerator.

	    // Authorization certificates are created by the AuthorizationCertGenerator
	    AuthorizationCertGenerator authorizationCertGenerator = new AuthorizationCertGenerator(cryptoManager);

	    // Next we generate keys for an authorization certificate.
	    KeyPair authorizationCertRequestSigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    // Next we generate keys for an authorization certificate.
	    KeyPair authorizationCertEncryptionKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

	    CertificateId authorizationCertId = new CertificateId(Hex.decode("9999999999"));
	    ValidityPeriod authorizationCertValidityPeriod = new ValidityPeriod(new Date(), DurationChoices.years, 35);


		PsidSsp[] appPermissions = new PsidSsp[1];
		appPermissions[0] = new PsidSsp(new Psid(6), null); // Insert proper app permissions here.

	    // Generate a certificate as an implicit certificate.
	    Certificate authorizationCert = authorizationCertGenerator.genAuthorizationCert(
	    		CertificateType.implicit, // Implicit or Explicit certificate
	    		authorizationCertId, // Certificate Id,
	    		authorizationCertValidityPeriod,
	    		region,
	    		appPermissions,
	    		cracaid, // insert proper cracaid here.
	    		99, // Some CrlSeries
	    		4,
	    		3,
	    		SignatureChoices.ecdsaNistP256Signature, //signingPublicKeyAlgorithm
	    		authorizationCertRequestSigningKeys.getPublic(), // signPublicKey, i.e public key in certificate
	    		authorityCACertificate, // signerCertificate
	    		authorityCASigningKeys.getPublic(), // signCertificatePublicKey,
	    		authorityCASigningKeys.getPrivate(),
	    		SymmAlgorithm.aes128Ccm, // symmAlgorithm
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256, // encPublicKeyAlgorithm
	    		authorizationCertEncryptionKeys.getPublic() // encryption public key
	    		);

	    // Implicit certificate needs to have it's private key reconstructed. R is given inside the ImplicitCertificateData (which is the actual type of implicit certificates)
	    PrivateKey authorizationCertSigningPrivateKey = cryptoManager.reconstructImplicitPrivateKey(authorizationCert,
	    		((ImplicitCertificateData) authorizationCert).getR(),
	    		SignatureChoices.ecdsaNistP256Signature,
	    		authorizationCertRequestSigningKeys.getPrivate(), authorityCASigningKeys.getPublic(),
	    		authorityCACertificate);

Certificate Encoding and Decoding Example

To encode and decode a certificate use:

	    // To encode a certificate to a byte array use the following method
	    byte[] certificateData = authorizationCert.getEncoded();

	    // To decode certificate data use the following constructor
	    Certificate decodedCertificate = new Certificate(certificateData);

Secured Data Example

To generate signed and/or encrypted Secured Data use the SecuredMessageGenerator:

	    // Secure Messages are created by the Secure Message Generator
	    SecuredDataGenerator securedMessageGenerator = new SecuredDataGenerator(SecuredDataGenerator.DEFAULT_VERSION, cryptoManager, HashAlgorithm.sha256, SignatureChoices.ecdsaNistP256Signature);

	    // It is then possible to create a signed message with the following code
	      // First generate a Header with
	    HeaderInfo hi = securedMessageGenerator.genHeaderInfo(
	    		123L, // psid Required,
	    		null, // generationTime Optional
	    		null, // expiryTime Optional
	    		null, // generationLocation Optional
	    		null, // p2pcdLearningRequest Optional
	    		null, // cracaid Optional
	    		null, // crlSeries Optional
	    		null, // encType Type of encryption when encrypting a message with a encryption key references in a signed message instead of a certificate. Optional
	    		null, // encryptionKey Optional
				null, // inlineP2pcdRequest Optional
		null // requestedCertificate Optional
	    		);

	    // This method can be used to sign the data
	    Ieee1609Dot2Data signedData = securedMessageGenerator.genSignedData(hi,
	    		"TestData".getBytes(), // The actual payload message to sign.
	    		SignerIdentifierType.HASH_ONLY, // One of  HASH_ONLY, SIGNER_CERTIFICATE, CERT_CHAIN indicating reference data of the signer to include in the message
	    		new Certificate[] {authorizationCert,authorityCACertificate, rootCACertificate}, // The chain is required even though it isn't included in
	    		  // the message if eventual implicit certificates need to have it's public key reconstructed.
	    		authorizationCertSigningPrivateKey); // Signing Key

	    // The message can be encrypted with the method
	      // First construct a list of recipient which have the public key specified either as a symmetric key, certificate or in header of signed data
	      // In this example we will use certificate as reciever, see package org.certificateservices.custom.c2x.ieee1609dot2.generator.recipient for more details.
	    Ieee1609Dot2Data encryptedData = securedMessageGenerator.encryptData(BasePublicEncryptionKeyChoices.ecdsaNistP256,
	    		  signedData.getEncoded(), new Recipient[] {new CertificateRecipient(enrollmentCredential)});
	      // It is also possible to encrypt using a pre shared key using the encryptDataWithPresharedKey() method.

	    // It is also possible to sign and encrypt in one go.
	    byte[] encryptedAndSignedMessage = securedMessageGenerator.signAndEncryptData(hi,
	    		"TestData2".getBytes(),
	    		SignerIdentifierType.HASH_ONLY,
	    		new Certificate[] {authorizationCert,authorityCACertificate, rootCACertificate},
	    		authorizationCertSigningPrivateKey, // Important to use the reconstructed private key for implicit certificates
	    		BasePublicEncryptionKeyChoices.ecdsaNistP256,
	    		new Recipient[] {new CertificateRecipient(enrollmentCredential)}).getEncoded();

	    // To decrypt and verify a signed message it is possible to use the following
	      // First build a truststore of trust anchors (root CA certificate or equivalent)
	    Map<HashedId8, Certificate> trustStore = securedMessageGenerator.buildCertStore(new Certificate[] {rootCACertificate});
	      // Second build a store of known certificate that might be referenced in the message.
	    Map<HashedId8, Certificate> certStore = securedMessageGenerator.buildCertStore(new Certificate[] {authorizationCert, authorityCACertificate});
	      // To decrypt build a reciever store of known decryption keys and related receiver info, this can be certificate, signed message containing encryption key
	      // in header, symmetric key or pre shared key.
	    Map<HashedId8, Receiver> recieverStore = securedMessageGenerator.buildRecieverStore(new Receiver[] { new CertificateReciever(enrollmentCredentialEncryptionKeys.getPrivate(), enrollmentCredential)});
		  // Finally perform the decryption with.
		DecryptAndVerifyResult decryptAndVerifyResult = securedMessageGenerator.decryptAndVerifySignedData(encryptedAndSignedMessage,
	    		certStore,
	    		trustStore,
	    		recieverStore,
	    		true, //requiredSignature true if message must be signed otherwise a IllegalArgument is throwm
	    		true //requireEncryption true if message must be encrypted otherwise a IllegalArgument is throwm
	    		);
		   // The decryptAndVerifyResult contains the inner opaque data, the related header info and signer identifier
		   // if related message was signed.

	      // It is also possible to use the methods decryptData or verifySignedData (or verifyReferencedSignedData) for alternative methods to verify and decrypt messages.

Secured Data Encoding and Decoding Example

To encode and decode a secured data use:

	    // To encode a secured message to a byte array use the following method.
	    byte[] messageData = signedData.getEncoded();

	    // To decode message data use the following constructor.
	    Ieee1609Dot2Data decodedMessage = new Ieee1609Dot2Data(messageData);

c2c-common's People

Contributors

pvendil avatar

Stargazers

 avatar Myung-jong Kim avatar buerwang avatar Geovandro Pereira avatar Mars avatar  avatar yxl avatar fong avatar Dan Avram avatar Jan avatar  avatar ChangBeom Park avatar  avatar Florian Petry avatar  avatar  avatar  avatar ID9527 avatar  avatar  avatar Leef avatar  avatar Mark Retallack avatar 小肚子 avatar suxiaoyv avatar Domenico Barra avatar Giuseppe Criscione avatar  avatar lu avatar blackshow avatar  avatar Shengtuo Hu avatar  avatar Antonio Sánchez avatar  avatar Per Sandström avatar A. Lochotzke avatar  avatar Tiago Pinto avatar Marvin avatar Alex avatar Midson avatar Wannes avatar wassim.znaidi avatar jakobssonan avatar

Watchers

RiShiE avatar samuel jebamani avatar blackshow avatar Mark Retallack avatar  avatar  avatar jakobssonan avatar  avatar Ali Kalsen avatar Kévin Leprêtre avatar Alex avatar Tiago Pinto avatar

c2c-common's Issues

convert certData to ASN.1

How do I convert the binary data of the certificate into the standard IEEE 1609.2 ASN.1 format and write it to the file

MAC Error

I am trying to enrol a Java simulated RSU. However, when I receive the enrolment response, I have:

`it.pki.ITSException: Unable to decrypt the response received from 20200804
at it.cits.security.pki.RSU.initialEnrollment(RSU.java:252)
at it.cits.security.pki.TestObtainAT.test(TestObtainAT.java:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:628)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:117)

Caused by: org.certificateservices.custom.c2x.etsits102941.v131.DecryptionFailedException: Error, couldn't decrypt EnrolmentResponseMessage(: Invalid cipher text when performing symmetric decrypt: mac check in CCM failed
at org.certificateservices.custom.c2x.etsits102941.v131.generator.ETSITS102941MessagesCaGenerator.decryptAndVerifyEnrolmentResponseMessage(ETSITS102941MessagesCaGenerator.java:408)
at it.cits.security.pki.RSU.initialEnrollment(RSU.java:246)
... 54 more
Caused by: java.security.GeneralSecurityException: Invalid cipher text when performing symmetric decrypt: mac check in CCM failed
at org.certificateservices.custom.c2x.common.crypto.DefaultCryptoManager.symmetricDecryptIEEE1609_2_2017(DefaultCryptoManager.java:831)
at org.certificateservices.custom.c2x.ieee1609dot2.generator.SecuredDataGenerator.decryptDataWithSecretKey(SecuredDataGenerator.java:459)
at org.certificateservices.custom.c2x.ieee1609dot2.generator.SecuredDataGenerator.decryptData(SecuredDataGenerator.java:475)
at org.certificateservices.custom.c2x.etsits102941.v131.generator.ETSITS102941MessagesCaGenerator.decryptAndVerifyEnrolmentResponseMessage(ETSITS102941MessagesCaGenerator.java:406)
... 55 more
Caused by: org.bouncycastle.crypto.InvalidCipherTextException: mac check in CCM failed
at org.bouncycastle.crypto.modes.CCMBlockCipher.processPacket(CCMBlockCipher.java:343)
at org.bouncycastle.crypto.modes.CCMBlockCipher.doFinal(CCMBlockCipher.java:146)
at org.certificateservices.custom.c2x.common.crypto.DefaultCryptoManager.symmetricDecryptIEEE1609_2_2017(DefaultCryptoManager.java:829)
... 58 more

`

I have been told that a similar issue happened during the last year's ETSI plug test. Any hints?

IEEE 1609.2 2016

@pvendil

I am looking for an implementation of IEEE 1609.2-2016. Your README states that this library supports 2015 version but IEEE 1609 was finalized on 3/1/2016. The previous US standard has been 2013. Does this mean that this product was developed based on preliminary specs? Would it work with the final version of the spec?

Thanks

Couldn't able to run ITSDemo.java

Hi ,

I am trying to generate certificates using c2c-common-0.9.8. Maven and grails are also installed.
But when I try to run ITSDemo.java through eclipse, it is showing " Cannot find class 'junit.framework.TestCase' on project build path. " some Build Path Problem.
I am stuck at this point. Please help me to proceed further.
I set proxy in pom.xml of Maven and it is building successfully when " mvn install " is given.

EtsiTs102941Data COER encoding

Hi @pvendil,

I'm running into some errors while encoding and decoding EtsiTs102941Data from c2c-common (v2.0.0-Beta4) to Python.
While the other datastructures (such as EtsiTs103097Data, EtsiTs103097Data-Signed, InnerEcRequestSignedForPop, etc..) are interpreted correctly in both languages, the EtsiTs102941Data isn't.
I was wondering if the encoding procedure in your library has changed for that datastructure.

For example, this is a Base64 encoded EtsiTs102941Data generated with c2c-common:

AQGAA4EAQAOAgYUAGlNvbWVFbnJvbENyZWRDYW5vbmljYWxOYW1lAYCAgxxz8bh10xe90S+q3vtivF3+kz8ZZOhHM9RVZH2CG2H8AICDSs6ULGmmugAdkHesdicFqC6SYT3GHXAyuzPxCwfdhaF8gQdlbnJvbGwxHBBbGIYABYMBAYAC8CMBAYACAm+AAgEyQAICbwAB7wcbj3KQgoCAVFnWmgodt6dVR3y/nrDtX4VOERsiTo8UXIJB1eejlGITn2Tmzcg36CuNXt8tWhjrap5jQumvRSrdNzbz6lb4Bg==

And it is read in Java without problems with:

byte[] data102941bytes = Base64.getDecoder().decode(<that string>);
EtsiTs102941Data testdata = new EtsiTs102941Data(data102941bytes);

At the same time in Python the library asn1tools with the asn files compiled from the ETSI Gitlab fails to decode it:

asn1compiler = asn1tools.compile_files(<Etsi ASN specification>, codec='oer')
etsi102941data2 = asn1compiler.decode('EtsiTs102941Data', base64.b64decode(<that string>))

On the other hand, the following python code:

data102941_content = {"protocolVersion": 3, "content": ("unsecuredData", inner_ec_signed_for_pop_bytes)}
data102941 = {"version": 1, "content": ("enrolmentRequest", data102941_content)}
data102941_bytes = asn1compiler.encode('EtsiTs102941Data', data102941)

produces this Base64 encoded EtsiTs102941Data which is read correctly in Python and not in c2c-common:

AYADgIHiA4EAQAOAgYsAIGVucm9sbWVudENyZWRlbnRpYWxDYW5vbmljYWxOYW1lAYCAg+vP21dSRvv5RuyV+dAcRldmm8HNmTgXoZKAN+mADosYAICDyDour0L2Eg07m5npv9dox7wuSs/3S29xDL7M1Qb85/d8gQdlbnJvbGwxHBBbGIYABYMBAYAC8CMBAYACAm+AAgEyQAICbwAAMXRKblwsgoCAvrb1ky7z7923yEyPIJTwDmXLt16f6N49dBOxKy+WNsAiwUmyMBhkhj2WQ4lWYWrNKoEb/5/b7Np7dSN976R69A==

c2c-common fails with this error when reading this python generated string:

java.io.IOException: Error decoding COER enumeration, no matching enumeration value exists for ordinal: 108
	at org.certificateservices.custom.c2x.asn1.coer.COEREncodeHelper.readEnumeratonValueAsEnumeration(COEREncodeHelper.java:190)
	at org.certificateservices.custom.c2x.asn1.coer.COEREnumeration.decode(COEREnumeration.java:70)
	at org.certificateservices.custom.c2x.asn1.coer.COERSequence.decode(COERSequence.java:296)
	at org.certificateservices.custom.c2x.asn1.coer.COERChoice.decode(COERChoice.java:102)
	at org.certificateservices.custom.c2x.asn1.coer.COERSequence.decode(COERSequence.java:296)
	at org.certificateservices.custom.c2x.etsits102941.v131.datastructs.messagesca.EtsiTs102941Data.<init>(EtsiTs102941Data.java:62)
	at main.LoadERString.main(LoadERString.java:16)

Keeping in mind that the other datastructures are correctly interpreted between the two languages, you shed some light on this matter?

GenKeyTag typo

questions of COERBitString

I don't have experience is this field, and I have some questions ,when COERBitString init during the testing process,look at the details as followings:
'org.certificateservices.custom.c2x.asn1.coer.COERBitStringSpec'
when "encoded" is "1001" value is 0x1001 how did you get length as "16"?
when "encoded" is "00" value is 0L how did you get length as "8"?
if i have a string "abc" ,how i can calculate length and value? look at my code follwing ,is there anything wrong with that, help me check please.
image

Time64 accuracy error

Hi,pvendil @pvendil

Time64 should be in microseconds,but it is actually in milliseconds.

Time64::=Uint64

This data structure is a 64-bit integer giving an estimate of the number of (TAI) microseconds since 00:00:00 UTC,1 January,2004.

After date transform to TAI , it return the value as seconds inclusive.
So it should be multiplied 1000000 not 1000.

Second*1000=Millisecond
Second*1000000=Microsecond
public Time64(Date timeStamp) {
    super();
    Moment moment = TemporalType.JAVA_UTIL_DATE.translate(timeStamp);
    // transform return value as seconds inclusive
    BigDecimal bd = moment.transform(TimeScale.TAI);

    this.value = bd.subtract(new BigDecimal(SECONDSBETWEENTAIZEROAND2004)).multiply(new BigDecimal(1000)).toBigInteger();

     //  this.value = bd.subtract(new BigDecimal(SECONDSBETWEENTAIZEROAND2004)).multiply(new BigDecimal(1000000)).toBigInteger();
  }
    /**
     * <p>Represents this timestamp as decimal value in given time scale. </p>
     *
     * @param   scale       time scale reference
     * @return  decimal value in given time scale as seconds inclusive fraction
     * @throws  IllegalArgumentException if this instance is out of range
     *          for given time scale
     */
    /*[deutsch]
     * <p>Stellt diese Zeit als Dezimalwert in der angegebenen Zeitskala
     * dar. </p>
     *
     * @param   scale       time scale reference
     * @return  decimal value in given time scale as seconds inclusive fraction
     * @throws  IllegalArgumentException if this instance is out of range
     *          for given time scale
     */
    public BigDecimal transform(TimeScale scale) {

        BigDecimal elapsedTime =
            new BigDecimal(this.getElapsedTime(scale)).setScale(9);
        BigDecimal nanosecond = new BigDecimal(this.getNanosecond(scale));
        return elapsedTime.add(nanosecond.movePointLeft(9));

    }

PsidGroupPermissions created incorrectly in ETSIAuthorityCertGenerator.java

Hello, I believe that following line:
https://github.com/pvendil/c2c-common/blob/987d78f451ebf5e81a6e807482967845d78cf9b8/src/main/java/org/certificateservices/custom/c2x/etsits103097/v131/generator/ETSIAuthorityCertGenerator.java#L307

should be correctly called like this:

PsidGroupPermissions pgp =  new PsidGroupPermissions(sp, null, null, new EndEntityType(true, false)); 

Calling it with values 1 and 0 which are default values for minChainDepth and chainDepthRange produces invalid COER structure according to ITU-T X.696:

31 Canonical Octet Encoding Rules
31.9 In the encoding of a sequence or set type, each component that is marked DEFAULT shall be encoded as absent if its value is identical to the default value.


Using nulls is suggested also by documentation:
https://github.com/pvendil/c2c-common/blob/987d78f451ebf5e81a6e807482967845d78cf9b8/src/main/java/org/certificateservices/custom/c2x/ieee1609dot2/datastructs/cert/PsidGroupPermissions.java#L76-L77

COERInteger encode negative number error

Hi,pvendil @pvendil

l found when the value is negative (e.g. -10000),it will be encode to 0000D8F0.
When decoding, it is calculated as 55536,-10000 need to be encoded to FFFFD8F0
When the value is negative,the buffer need to be filled with 0xff

private void serializeSigned(DataOutputStream out) throws IOException {
		byte[] val = value.toByteArray();

		int signOctet = 0;
		if(val[0] == 0x00 && val.length > 1){
			signOctet++;
		}
		
		if(isSignedAndBetween(NEGATIVE_TWO_PWR_63, TWO_PWR_63_MINUS_1)){
			byte[] buffer = new byte[getSignedBufferSize()];
                        // if value is negative buffer need to be filled with 0xff
			System.arraycopy(val, signOctet, buffer, buffer.length - (val.length -signOctet), val.length -signOctet);
			out.write(buffer);
		}else{
			COEREncodeHelper.writeLengthDeterminant(val.length-signOctet, out);
			out.write(val, signOctet, val.length -signOctet);
		}
	}

Cannot validate any output from the ITS Demo

I modified the ITSDemo.java file to write generated CA/Certs/Keys/Messages to a file.

image

The ITSDemo.java JUnit test passes - output looks good

image

I am trying to use the following site as referenced in the documentation to verify the output

https://werkzeug.dcaiti.tu-berlin.de/etsi/ts103097/

No matter what data I enter here from the output of the ITSDemo test will not validate. Is there any more information on how /what to take from the generated output so that it can be successfully validated.

best regards

Patrick

Source folder src/test/resources missing

Hi,

when building the project, eclipse returns an error stating that the above source folder is missing. This might be a reason why the tests don't run properly on my computer returing a Class.

However, when deleting the source folder from the build path or the classpath file, other errors occur, e.g. in the class COERBitString.groovy. I couldn't solve that error or even figure it out. Maybe you can help me @pvendil

Cheers,

McLovin

COERBoolean

Hello @pvendil,

I have been analising the code and noticed that in the COEDBollean encoded structure the true and false values does not match what is expected by the ITU-T X.696 standard described in IEEE's Std 1609.2-2016. That document states:

"The encoding of a Boolean value shall be a single octet. The octet value 0 denotes the Boolean value FALSE and a non-zero octet value denotes the Boolean value TRUE. NOTE - In CANONICAL-OER, only the octet value 'FF'H can be used to encode the value TRUE ... "

In your implementation's code the false value is FF'H and the true value is 00'H, shouldn't it be the opposite?
Am i misunderstanding something or is there a bug in your implementation?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.