Skip to content

Commit 8f3c629

Browse files
committed
Fix CV request generation.
It includes the parameter --req-car to specify the expected CAR for signature. Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
1 parent 7291c80 commit 8f3c629

4 files changed

Lines changed: 42 additions & 31 deletions

File tree

cvc/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@
1818
*/
1919
"""
2020

21-
__version__ = "1.2.1"
21+
__version__ = "1.2.2"

cvc/certificates.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ def decode(self, data):
3838
self.__a = ASN1().decode(self.__data)
3939
return self
4040

41-
def body(self, pubkey=None, scheme=None, car=None, chr=None, role=None, valid=None, since=None, extensions=None):
41+
def body(self, pubkey=None, scheme=None, car=None, chr=None, role=None, valid=None, since=None, extensions=None, req=False):
4242
if (self.__data != None):
4343
return self.cert().find(0x7f4e)
44-
self.__a = ASN1().add_tag(0x7f4e, self.cpi().car(car).pubkey(pubkey, scheme, car == chr).chr(chr).role(role).valid(valid, since).extensions(extensions).encode())
44+
self.__a = ASN1().add_tag(0x7f4e, self.cpi().car(car).pubkey(pubkey, scheme, req).chr(chr).role(role).valid(valid, since).extensions(extensions).encode())
4545
return self
4646

4747
def extensions(self, extensions=None):
@@ -131,10 +131,10 @@ def sign(self, key, scheme):
131131
self.__a = self.__a.add_tag(0x5f37, bytearray(signature))
132132
return self
133133

134-
def cert(self, pubkey=None, scheme=None, signkey=None, signscheme=None, car=None, chr=None, role=None, valid=None, since=None, extensions=None):
134+
def cert(self, pubkey=None, scheme=None, signkey=None, signscheme=None, car=None, chr=None, role=None, valid=None, since=None, extensions=None, req=False):
135135
if (self.__data != None):
136136
return self.req().find(0x7f21)
137-
self.__a = ASN1().add_tag(0x7f21, self.body(pubkey, scheme, car, chr, role, valid, since, extensions).sign(signkey, signscheme).encode())
137+
self.__a = ASN1().add_tag(0x7f21, self.body(pubkey, scheme, car, chr, role, valid, since, extensions, req or chr==car).sign(signkey, signscheme).encode())
138138
return self
139139

140140
def req(self, pubkey=None, scheme=None, signkey=None, signscheme=None, car=None, chr=None, outercar=None, outerkey=None, outerscheme=None, extensions=None):
@@ -143,15 +143,15 @@ def req(self, pubkey=None, scheme=None, signkey=None, signscheme=None, car=None,
143143
if (aut):
144144
return aut
145145
return ASN1().decode(self.__data)
146-
cert = self.cert(pubkey, scheme, signkey, signscheme, car, chr, role=None, valid=None, since=None, extensions=extensions)
146+
cert = self.cert(pubkey, scheme, signkey, signscheme, car, chr, role=None, valid=None, since=None, extensions=extensions, req=True)
147147
if (outercar != None and outerkey != None and outerscheme != None):
148148
self.__a = ASN1().add_tag(0x67, cert.car(outercar).sign(outerkey, outerscheme).encode())
149149
return self
150150

151151
def is_req(self):
152152
if (self.__data != None):
153153
b = self.__a
154-
ret = self.__a.find(0x67) != None
154+
ret = self.__a.find(0x67) != None or self.body().find(0x5f25) == None
155155
self.__a = b
156156
return ret
157157
return False

cvc/tools/cvc_create.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ def parse_args():
3535
parser.add_argument('-o','--out-cert', help='Generated certificate file', metavar='FILENAME')
3636
parser.add_argument('-r','--role', help='The role of entity', choices=['cvca','dv_domestic','dv_foreign','terminal'])
3737
parser.add_argument('-t','--type', help='The type of terminal. If not provided, it creates a certificate request', choices=['at','is','st'])
38-
parser.add_argument('--chat', help='Raw Card Holder Authorization Template')
3938
parser.add_argument('--valid', help='Days of validity since today or date provided by --since', default=90)
4039
parser.add_argument('-k','--sign-key', help='Private key to sign the certificate.', required=True, metavar='FILENAME')
41-
parser.add_argument('--sign-as', help='CV certificate of signing entity. If not provided, the certificate is self-signed', metavar='FILENAME')
42-
parser.add_argument('--outer-as', help='CV certificate for outer signature', metavar='FILENAME')
43-
parser.add_argument('--outer-key', help='Private key for outer signature', metavar='FILENAME')
40+
parser.add_argument('--sign-as', help='CV certificate of signing entity. If not provided, the certificate is self-signed [generates a certificate]', metavar='FILENAME')
41+
parser.add_argument('--outer-as', help='Outer certificate for CV request', metavar='FILENAME')
42+
parser.add_argument('--outer-key', help='Private key for outer signature of CV request', metavar='FILENAME')
4443
parser.add_argument('-p','--public-key', help='The public key contained in the certificate. If not provided, it is derived from the sign-key', metavar='FILENAME')
4544
parser.add_argument('-q','--request', help='Generates a certificate based on a request', metavar='FILENAME')
4645
parser.add_argument('--out-key', help='File to store the generated private key [default CHR.pkcs8]', metavar='FILENAME')
@@ -51,6 +50,7 @@ def parse_args():
5150
"RSA_v1_5_SHA_512", "RSA_PSS_SHA_1",
5251
"RSA_PSS_SHA_256", "RSA_PSS_SHA_512"])
5352
parser.add_argument('-c','--chr', help='Certificate Holder Reference')
53+
parser.add_argument('-a','--req-car', help='Certificate Authority Reference expected for CV request [generates a request]')
5454
parser.add_argument('--write-dg17', help='Allow writing DG 17 (Normal Place of Residence)', action='store_true')
5555
parser.add_argument('--write-dg18', help='Allow writing DG 18 (Community ID)', action='store_true')
5656
parser.add_argument('--write-dg19', help='Allow writing DG 19 (Residence Permit I)', action='store_true')
@@ -202,22 +202,30 @@ def main(args):
202202
elif (isinstance(pub_key, ec.EllipticCurvePublicKey)):
203203
puboid = oid.ID_TA_ECDSA_SHA_256
204204

205-
if (args.sign_as and typ and not args.outer_as and not args.outer_key):
205+
if (args.sign_as and typ and not args.outer_as and not args.outer_key): # Cert
206206
car, signscheme = parse_as(args.sign_as)
207-
else:
208-
car = args.chr.encode()
207+
else: # Req
208+
if (args.req_car):
209+
car = args.req_car.encode()
210+
else:
211+
car = args.chr.encode()
209212
signscheme = puboid
210213

211214
if (not chr):
212215
chr = args.chr.encode()
213-
if (args.outer_as and args.outer_key):
214-
outercar, outerscheme = parse_as(args.outer_as)
215-
outerkey = load_private_key(args.outer_key)
216-
cert = CVC().req(pub_key, puboid, sign_key, signscheme, car=chr, chr=chr, outercar=outercar, outerkey=outerkey, outerscheme=outerscheme)
216+
if (args.req_car or (args.outer_as and args.outer_key)):
217+
if (args.outer_as and args.outer_key):
218+
outercar, outerscheme = parse_as(args.outer_as)
219+
outerkey = load_private_key(args.outer_key)
220+
else:
221+
outercar,outerscheme,outerkey = None,None,None
222+
cert = CVC().req(pub_key, puboid, sign_key, signscheme, car=car, chr=chr, outercar=outercar, outerkey=outerkey, outerscheme=outerscheme)
223+
ext = 'cvreq'
217224
else:
218225
cert = CVC().cert(pub_key, puboid, sign_key, signscheme, car=car, chr=chr, role=typ, valid=args.valid if typ else None)
226+
ext = 'cvcert'
219227

220-
with open(args.out_cert if args.out_cert != None else chr.decode()+'.cvcert','wb') as f:
228+
with open(args.out_cert if args.out_cert != None else chr.decode()+'.'+ext,'wb') as f:
221229
f.write(cert.encode())
222230

223231
def run():

cvc/tools/cvc_print.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,25 +84,28 @@ def main(args):
8484
print(f' Bytes: {hexlify(CVC().decode(cdata).role().find(0x53).data()).decode()}')
8585
print(f' Since: {bcd2date(CVC().decode(cdata).valid()).strftime("%Y-%m-%d")}')
8686
print(f' Expires: {bcd2date(CVC().decode(cdata).expires()).strftime("%Y-%m-%d")}')
87-
if (CVC().decode(cdata).verify(cert_dir=cert_dir)):
87+
isreq = CVC().decode(cdata).is_req()
88+
if (CVC().decode(cdata).verify(cert_dir=cert_dir, dica=cdata if isreq else None)):
8889
print('Inner signature is VALID')
8990
ret = True
9091
else:
9192
print('Inner signature is NOT VALID')
9293
ret = False
9394
if (car != chr):
94-
try:
95-
while (car != chr):
96-
with open(os.path.join(cert_dir,bytes(car)), 'rb') as f:
97-
adata = f.read()
98-
ret = ret and CVC().decode(adata).verify(cert_dir=cert_dir)
99-
chr = CVC().decode(adata).chr()
100-
car = CVC().decode(adata).car()
101-
except FileNotFoundError:
102-
print(f'[Warning: File {car.decode()} not found]')
103-
ret = False
95+
if (isreq):
96+
ret = CVC().decode(cdata).verify(cert_dir=cert_dir, dica=cdata)
97+
else:
98+
try:
99+
while (car != chr):
100+
with open(os.path.join(cert_dir,bytes(car)), 'rb') as f:
101+
adata = f.read()
102+
ret = ret and CVC().decode(adata).verify(cert_dir=cert_dir)
103+
chr = CVC().decode(adata).chr()
104+
car = CVC().decode(adata).car()
105+
except FileNotFoundError:
106+
print(f'[Warning: File {car.decode()} not found]')
107+
ret = False
104108
else:
105-
isreq = CVC().decode(cdata).is_req()
106109
if (isreq):
107110
print(f'Outer CAR: {CVC().decode(cdata).outer_car().decode()}')
108111
outret = CVC().decode(cdata).verify(cert_dir=cert_dir, outer=True)

0 commit comments

Comments
 (0)