-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Datatype of X509SerialNumber #54
Comments
Hi @Thoren-G, Too bad that exactly one single occurrence of such a special type made its made into the standard. ;-) |
OpenV2G had a recent update regarding this in 2022 in the iso1X509IssuerSerialType struct, their solution was an array of 20 bytes; struct {
/** a sign value */
int negative;
/* container size */
/* size_t size; iso1X509IssuerSerialType_X509SerialNumber_BYTES_SIZE */
/** array data container */
/* For negative values, the Unsigned Integer holds the
* magnitude of the value minus 1 */
uint8_t data[iso1X509IssuerSerialType_X509SerialNumber_BYTES_SIZE];
/** array length (len <= size) */
size_t len;
} X509SerialNumber; We ought to look at this implementation. |
I think I resolved this in #65 |
IMHO, "[RFC5280] 4.1.2.2. Serial Number"(below) might have a typo.
It seems that the "20 octests" might be understood more correctly with the meaning of "20 digits". |
I very much doubt that's an error nor that they mean something other than the integer length in bytes. Octet is another term for byte, they keep calling it an integer and never a string. And considering that openv2g updated this specific datatype to fill 20 bytes should also be enough reason to follow their example; EVs may use this. I also found this insight on SO saying 16 bytes may be enough, which is still twice as much as a u64. https://stackoverflow.com/questions/37031043/minimum-and-maximum-length-of-x509-serialnumber So especially since this concerns security and data from outside sources, and following from other examples, we ought to stick on the safe side. |
I understand your concern, but I didn't mean 'octect' is string. (ie, it's just a big NUMBER, not likely UUID) (2) in "[RFC2459] 4.1.2.2 Serial number"
in my understanding, ASN.1 also have an ambiguity of interpreting INTEGER(https://www.oss.com/asn1/knowledge-center/asn1-java/asn1java-integer-type-limitations.html) type. (3) I can't tell EV(ex, Vector Infomatik) may use different appoach, but the latest OpenV2G generate different EXI stream(near end of stream, see below log) with SwitchEV(as I know SwitchEV already have coworked with the Hubject). IMHO, OpenV2G v0.9.4(30 January 2018) is the stable release(inludes fixing eMAID fragment issue), and I couldn't find where it(supporting big integer) from. (no related issue ticket found) [FragmentEncoding] [SwitchEV, OpenV2G v0.9.4] [OpenV2G v0.9.5] |
Even if you think that's reasonable, that's not the common understanding of the definition, and you cannot just fiddle with than. I agree with @SiebrenW's interpretation that we need up to 160 bits.
I would go for 0.9.5:
Right here:
That is indeed an issue, what to consider as a reference. |
xmldsig-core-schema.xsd unfortunately pulled in a lot of unfortunate XML "junk", and stuff that is only needed once, and a pain to support (see e.g. #56). |
I agree that we'd better(should) to implement standard as possible as we could. |
If we were to send this to the EV then I would agree, but considering the EVSE gets this X509SerialNumber from the EV and we don't send it, we have to handle anything the EV may send towards us. Putting this in risk factors: the risk not to support it is present. The risk to support it is maybe a bit of overhead (not as trivial to use this as a normal int, but we're not doing any operations on this int I hope), but otherwise an EV will not complain if we support bigger ints than i64. |
I tested with a python script using OpenEXI that checks for schema validity using lxml and encodes/decodes some EXI messages to/from XML. <?xml version="1.0" encoding="UTF-8"?>
<ns0:CertificateInstallationReq xmlns:ns0="urn:iso:std:iso:15118:-20:CommonMessages">
<ns1:Header xmlns:ns1="urn:iso:std:iso:15118:-20:CommonTypes">
<ns1:SessionID>3030303030303030</ns1:SessionID>
<ns1:TimeStamp>1707896956850052</ns1:TimeStamp>
</ns1:Header>
<ns0:OEMProvisioningCertificateChain ns0:Id="ID1">
<ns0:Certificate>3q2+7w==</ns0:Certificate>
<ns0:SubCertificates>
<ns0:Certificate>ul66EQ==</ns0:Certificate>
</ns0:SubCertificates>
</ns0:OEMProvisioningCertificateChain>
<ns0:ListOfRootCertificateIDs>
<ns1:RootCertificateID xmlns:ns1="urn:iso:std:iso:15118:-20:CommonTypes">
<ns2:X509IssuerName xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">the name</ns2:X509IssuerName>
<ns2:X509SerialNumber xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">590295810358705651712</ns2:X509SerialNumber>
</ns1:RootCertificateID>
</ns0:ListOfRootCertificateIDs>
<ns0:MaximumContractCertificateChains>2</ns0:MaximumContractCertificateChains>
<ns0:PrioritizedEMAIDs>
<ns0:EMAID>some emaid</ns0:EMAID>
</ns0:PrioritizedEMAIDs>
</ns0:CertificateInstallationReq> auto exi = "\x01\xFE\x80\x02\x00\x00\x00\x46\x80\x1c\x04\x18\x18\x18\x18\x18\x18\x18\x18\x08\x49\xfb\x4f\xba\xba\xa8\x40\x32\x02\xa4\xa2\x18\x80\x9b\xd5\xb7\xdd\xe0\x04\xba\x5e\xba\x11\x20\x0a\x74\x68\x65\x20\x6e\x61\x6d\x65\x08\x08\x08\x08\x08\x08\x08\x08\x08\x04\x01\x00\x80\x18\xe6\xde\xda\xca\x40\xca\xda\xc2\xd2\xc8\x40"; Back is also fine. Result: <?xml version="1.0" encoding="UTF-8"?>
<s1:CertificateInstallationReq xmlns:s1="urn:iso:std:iso:15118:-20:CommonMessages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:s0="http://www.w3.org/2000/09/xmldsig#"
xmlns:s2="urn:iso:std:iso:15118:-20:CommonTypes">
<s2:Header>
<s2:SessionID>3030303030303030</s2:SessionID>
<s2:TimeStamp>1707896956850052</s2:TimeStamp>
</s2:Header>
<s1:OEMProvisioningCertificateChain s1:Id="ID1">
<s1:Certificate>3q2+7w==</s1:Certificate>
<s1:SubCertificates>
<s1:Certificate>ul66EQ==</s1:Certificate>
</s1:SubCertificates>
</s1:OEMProvisioningCertificateChain>
<s1:ListOfRootCertificateIDs>
<s2:RootCertificateID>
<s0:X509IssuerName>the name</s0:X509IssuerName>
<s0:X509SerialNumber>590295810358705651712</s0:X509SerialNumber>
</s2:RootCertificateID>
</s1:ListOfRootCertificateIDs>
<s1:MaximumContractCertificateChains>2</s1:MaximumContractCertificateChains>
<s1:PrioritizedEMAIDs>
<s1:EMAID>some emaid</s1:EMAID>
</s1:PrioritizedEMAIDs>
</s1:CertificateInstallationReq> |
FYI, I find that the "Serial number" of 'Hubject EU V2G Root CA G2'(https://www.hubject.com/download-pki) is also BigInt('BB BB BC 1A C4 5A D2 DF E5 B1 D8 73 C3 5C 84'), so I agree that we should support it. (the remaining question is the implementation of OpenV2G v0.9.5 is correct or not. (compared to SwitchEV's)) |
Summary of lengthy comment (sorry! 😟)
Hubject PKI: EVerest fails after CertificateInstallationReq messageI generated a set of certificates based on Hubject's QA environment. $ openssl x509 -in certs/ca/v2g/V2G_ROOT_CA.pem -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
69:ab:00:d2:59:bb:df:42:ce:80:52:9a:d3:0c:e5:ed
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = DE, O = Hubject GmbH, DC = V2G, CN = V2G Root CA QA G1
⋮ As you can see, this certificate also has large serial number ( When I configure EVerest to use this set of certificates, the process will fail due to timeout after receiving CertificateInstallationReq. The log reads:
But on TCP/TLS level, I can see that (simulated) vehicle actually sends a valid CertificateInstallationReq message. I interpret the log output in the way that EVerest was not able to decode this CertificateInstallationReq message. Reproducing w/o Hubject certificates and example CertificateInstallationReq message...
The same behavior can be reproduced by changing value of option diff --git a/iso15118/shared/pki/create_certs.sh b/iso15118/shared/pki/create_certs.sh
index eb7994b..aad6ddf 100755
--- a/iso15118/shared/pki/create_certs.sh
+++ b/iso15118/shared/pki/create_certs.sh
@@ -220,7 +220,7 @@ openssl req -new -key $CLIENT_V2G_PATH/V2G_ROOT_CA.key -passin pass:$password -c
# - each issued certificate must contain a unique serial number assigned by the CA (must be unique within the issuers number range) -> -set_serial
# - save the certificate at the location provided -> -out
# - make the certificate valid for 40 years (give in days) -> -days
-openssl x509 -req -in $CSR_PATH/V2G_ROOT_CA.csr -extfile configs/v2gRootCACert.cnf -extensions ext -signkey $CLIENT_V2G_PATH/V2G_ROOT_CA.key -passin pass:$password $SHA -set_serial 12345 -out $CA_V2G_PATH/V2G_ROOT_CA.pem -days $VALIDITY_V2G_ROOT_CERT
+openssl x509 -req -in $CSR_PATH/V2G_ROOT_CA.csr -extfile configs/v2gRootCACert.cnf -extensions ext -signkey $CLIENT_V2G_PATH/V2G_ROOT_CA.key -passin pass:$password $SHA -set_serial 140456838985911039497347770407602415085 -out $CA_V2G_PATH/V2G_ROOT_CA.pem -days $VALIDITY_V2G_ROOT_CERT
# 2) Create an intermediate CPO sub-CA 1 certificate which is directly signed Here is an example of a CertificateInstallationReq message, that EVerest cannot decode. Hex Stream including V2G header:
Decoded to XML with EXIficient (X509SerialNumber is displayed correctly): <?xml version="1.0" encoding="UTF-8"?>
<ns7:V2G_Message xmlns:ns7="urn:iso:15118:2:2013:MsgDef"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns3="http://www.w3.org/2001/XMLSchema"
xmlns:ns4="http://www.w3.org/2000/09/xmldsig#"
xmlns:ns5="urn:iso:15118:2:2013:MsgBody"
xmlns:ns6="urn:iso:15118:2:2013:MsgDataTypes"
xmlns:ns8="urn:iso:15118:2:2013:MsgHeader">
<ns7:Header>
<ns8:SessionID>A9C94BF7FEFDF7DE</ns8:SessionID>
<ns4:Signature>
<ns4:SignedInfo>
<ns4:CanonicalizationMethod Algorithm="http://www.w3.org/TR/canonical-exi/"/>
<ns4:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/>
<ns4:Reference URI="#id1">
<ns4:Transforms>
<ns4:Transform Algorithm="http://www.w3.org/TR/canonical-exi/"/>
</ns4:Transforms>
<ns4:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ns4:DigestValue>6Xq7T6deVQWoO+EeJy9HlSz2hwjsvk6WD6ekNhB1sBI=</ns4:DigestValue>
</ns4:Reference>
</ns4:SignedInfo>
<ns4:SignatureValue>fTaZ58/wfdRjC6CANSqzvlj8Xstbk8tqgohzqhAyl4xPoLBdCTn/VeMQQISVOOpq8yWy6CjqQ0rmXGReHthWLg==</ns4:SignatureValue>
</ns4:Signature>
</ns7:Header>
<ns7:Body>
<ns5:CertificateInstallationReq ns5:Id="id1">
<ns5:OEMProvisioningCert>MIIB4jCCAYigAwIBAgICMEAwCgYIKoZIzj0EAwIwSDESMBAGA1UEAwwJT0VNU3ViQ0EyMRAwDgYDVQQKDAdFVmVyZXN0MQswCQYDVQQGEwJERTETMBEGCgmSJomT8ixkARkWA09FTTAeFw0yNDA5MDcxMjAwNTBaFw0yODA5MDYxMjAwNTBaMEoxFDASBgNVBAMMC09FTVByb3ZDZXJ0MRAwDgYDVQQKDAdFVmVyZXN0MQswCQYDVQQGEwJERTETMBEGCgmSJomT8ixkARkWA09FTTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABP4HNijSZvATe+evtLGbPkHwFLeWTudwFBJTwJ8AV84S91Ov9a5iiL87D/n/0wD9YxnaUeCf/C2LhPmqfhiSnpajYDBeMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgOIMB0GA1UdDgQWBBQXDVOJswK4sHr0ANpCfOJhdYkNxzAfBgNVHSMEGDAWgBS4clA0lEg56CO9NtnWg/0ypfQvMTAKBggqhkjOPQQDAgNIADBFAiEA+bt224rPzmrVNO3R5dfomIEIX784TQpXuERM12gyUvECIEX55dnxI4I+NLzmWyEDij9fKzxOtTAbQhRzBq2KyjcZ</ns5:OEMProvisioningCert>
<ns5:ListOfRootCertificateIDs>
<ns6:RootCertificateID>
<ns4:X509IssuerName><Name(CN=V2GRootCA,O=EVerest,C=DE,DC=V2G)></ns4:X509IssuerName>
<ns4:X509SerialNumber>140456838985911039497347770407602415085</ns4:X509SerialNumber>
</ns6:RootCertificateID>
</ns5:ListOfRootCertificateIDs>
</ns5:CertificateInstallationReq>
</ns7:Body>
</ns7:V2G_Message> Correct implementation crucial for verification of signature in CertificateInstallationReqEarly EXI implementations of Vector had a bug in encoding/decoding of X509SerialNumber. This bug never surfaced when it was tested against their own implementation. But when they testing against other implementations, the verification of signature in CertificateInstallationReq would fail for the exact reason explained by @kwoyhope. Possible insights from EXIficientA long time ago when the above problem in Vector's EXI implementation was discovered, I would manually check CertificateInstallationReq messages with EXIficient. This would only work for the fixed Vector implementation and not for the older buggy one. So I assume that EXIficient it's compatible with Vector's implementation. I checked the example provided above in this comment with EXIficient. Both EXI data –"[SwitchEV, OpenV2G v0.9.4]" and "[OpenV2G v0.9.5]"– decode successfully to identical XML. When I encode the same data again, the resulting EXI is identical to "[SwitchEV, OpenV2G v0.9.4]". $ sha1sum *
56d73a053224a707307e7921f559b6665a4cd817 example_1_OpenV2G_v0_9_5
6e54e0044684268178852908747a7bc7b7bd6c13 example_1_OpenV2G_v0_9_5.xml
a1ba0da5bf0d735cbca95294fc8caee47c42eec3 example_1_OpenV2G_v0_9_5.xml.exi
a1ba0da5bf0d735cbca95294fc8caee47c42eec3 example_1_SwitchEV_OpenV2G_v0_9_4
6e54e0044684268178852908747a7bc7b7bd6c13 example_1_SwitchEV_OpenV2G_v0_9_4.xml
a1ba0da5bf0d735cbca95294fc8caee47c42eec3 example_1_SwitchEV_OpenV2G_v0_9_4.xml.exi ⇒ If the EXI data in above comment has been generated correctly (i.e., all configuration parameters identical etc.), this means that "[OpenV2G v0.9.5]" breaks compatibility with EXIficient and probably other implementations. I also ran EXIficient against the example from @SiebrenW's comment and I got identical results. So, no compatibility problems. This makes me wonder why EVerest cannot handle the CertificateInstallationReq messages described above. Does this only occur in ISO15118-2 and not in ISO15118-20? I would definitely be grateful for a fix! |
Hi @acnixvkh,
This was basically down to the fact that the EXI integer decoding was broken for large numbers, and resulted not in an incorrect number, but in a decode failure. We recently merged the pull request #65 which fixes this. It looks like it decodes your content:
correctly, to the correct number (but depends on the correct interpretation of the API). We have another PR open to change the representation of the number in the API: #87 We also need to check that our encoding conforms to what seems to be the consent of [OpenV2G v0.9.5] vs. [SwitchEV, OpenV2G v0.9.4]". It's hard for us to compare, as we haven't written our own fragment encoders and decoders for everything. |
Hello again,
I have discovered a problem related to the X509SerialNumber inside the CertificateInstallationReq and CertificateUpdateReq.
The X509SerialNumber can be up to 20 octets by definition (RFC5280 4.1.2.2).
The XSD defines it as an xs:integer type, which has no maximum.
However, cbEXIgen handles xs:integer as int32. This will cause the decoder to fail for long serial numbers.
This problem seems to effect all standards, but for DIN the corresponding encode and decode functions do exist but are never used. So this is actually only a problem for ISO-2 and ISO-20.
Best regards
The text was updated successfully, but these errors were encountered: