17 |
17 |
CertificateStatusInvalidException, CertificateNotFoundException, CertificateAlreadyRevokedException
|
18 |
18 |
# responsibility.
|
19 |
19 |
from src.services.key_service import KeyService
|
|
20 |
from src.utils.logger import Logger
|
|
21 |
from src.utils.util import dict_to_string
|
20 |
22 |
|
21 |
23 |
TREE_NODE_TYPE_COUNT = 3
|
22 |
24 |
|
... | ... | |
67 |
69 |
|
68 |
70 |
:rtype: CreatedResponse
|
69 |
71 |
"""
|
|
72 |
|
|
73 |
Logger.info(f"\n\t{request.referrer}"
|
|
74 |
f"\n\t{request.method} {request.path} {request.scheme}")
|
|
75 |
|
70 |
76 |
required_keys = {SUBJECT, USAGE, VALIDITY_DAYS} # required fields of the POST req
|
71 |
77 |
|
72 |
78 |
if request.is_json: # accept JSON only
|
73 |
79 |
body = request.get_json()
|
|
80 |
|
|
81 |
Logger.info(f"\n\tRequest body:"
|
|
82 |
f"\n{dict_to_string(body)}")
|
|
83 |
|
74 |
84 |
if not all(k in body for k in required_keys): # verify that all keys are present
|
|
85 |
Logger.error(f"Invalid request, missing parameters")
|
75 |
86 |
return E_MISSING_PARAMETERS, C_BAD_REQUEST
|
76 |
87 |
|
77 |
88 |
if not isinstance(body[VALIDITY_DAYS], int): # type checking
|
|
89 |
Logger.error(f"Invalid request, wrong parameter '{VALIDITY_DAYS}'.")
|
78 |
90 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
79 |
91 |
|
80 |
92 |
subject = Subject.from_dict(body[SUBJECT]) # generate Subject from passed dict
|
81 |
93 |
|
82 |
94 |
if subject is None: # if the format is incorrect
|
|
95 |
Logger.error(f"Invalid request, wrong parameter '{SUBJECT}'.")
|
83 |
96 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
84 |
97 |
|
85 |
98 |
usages_dict = {}
|
86 |
99 |
|
87 |
100 |
if not isinstance(body[USAGE], dict): # type checking
|
|
101 |
Logger.error(f"Invalid request, wrong parameter '{USAGE}'.")
|
88 |
102 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
89 |
103 |
|
90 |
104 |
for k, v in body[USAGE].items(): # for each usage
|
91 |
105 |
if k not in CertController.KEY_MAP: # check that it is a valid usage
|
|
106 |
Logger.error(f"Invalid request, wrong parameter '{USAGE}'[{k}].")
|
92 |
107 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST # and throw if it is not
|
93 |
108 |
usages_dict[CertController.KEY_MAP[k]] = v # otherwise translate key and set
|
94 |
109 |
|
... | ... | |
105 |
120 |
issuer = self.certificate_service.get_certificate(body[CA]) # get base issuer info
|
106 |
121 |
|
107 |
122 |
if issuer is None: # if such issuer does not exist
|
|
123 |
Logger.error(f"No certificate authority with such unique ID exists 'ID = {key.private_key_id}'.")
|
108 |
124 |
self.key_service.delete_key(key.private_key_id) # free
|
109 |
125 |
return E_NO_ISSUER_FOUND, C_BAD_REQUEST # and throw
|
110 |
126 |
|
111 |
127 |
issuer_key = self.key_service.get_key(issuer.private_key_id) # get issuer's key, which must exist
|
112 |
128 |
|
113 |
129 |
if issuer_key is None: # if it does not
|
|
130 |
Logger.error(f"Internal server error (corrupted database).")
|
114 |
131 |
self.key_service.delete_key(key.private_key_id) # free
|
115 |
132 |
return E_CORRUPTED_DATABASE, C_INTERNAL_SERVER_ERROR # and throw
|
116 |
133 |
|
... | ... | |
131 |
148 |
return {"success": True,
|
132 |
149 |
"data": cert.certificate_id}, C_CREATED_SUCCESSFULLY
|
133 |
150 |
else: # if this fails, then
|
|
151 |
Logger.error(f"Internal error: The certificate could not have been created.")
|
134 |
152 |
self.key_service.delete_key(key.private_key_id) # free
|
135 |
153 |
return {"success": False, # and wonder what the cause is,
|
136 |
154 |
"data": "Internal error: The certificate could not have been created."}, C_BAD_REQUEST
|
137 |
155 |
# as obj/None carries only one bit
|
138 |
156 |
# of error information
|
139 |
157 |
else:
|
|
158 |
Logger.error(f"The request must be JSON-formatted.")
|
140 |
159 |
return E_NOT_JSON_FORMAT, C_BAD_REQUEST # throw in case of non-JSON format
|
141 |
160 |
|
142 |
161 |
def get_certificate_by_id(self, id):
|
... | ... | |
149 |
168 |
|
150 |
169 |
:rtype: PemResponse
|
151 |
170 |
"""
|
|
171 |
|
|
172 |
Logger.info(f"\n\t{request.referrer}"
|
|
173 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
174 |
f"\n\tCertificate ID = {id}")
|
152 |
175 |
try:
|
153 |
176 |
v = int(id)
|
154 |
177 |
except ValueError:
|
|
178 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
155 |
179 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
156 |
180 |
|
157 |
181 |
cert = self.certificate_service.get_certificate(v)
|
158 |
182 |
|
159 |
183 |
if cert is None:
|
|
184 |
Logger.error(f"No such certificate found 'ID = {v}'.")
|
160 |
185 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA
|
161 |
186 |
else:
|
162 |
187 |
return {"success": True, "data": cert.pem_data}, C_SUCCESS
|
... | ... | |
171 |
196 |
|
172 |
197 |
:rtype: CertificateResponse
|
173 |
198 |
"""
|
|
199 |
|
|
200 |
Logger.info(f"\n\t{request.referrer}"
|
|
201 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
202 |
f"\n\tCertificate ID = {id}")
|
|
203 |
|
174 |
204 |
try:
|
175 |
205 |
v = int(id)
|
176 |
206 |
except ValueError:
|
|
207 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
177 |
208 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
178 |
209 |
|
179 |
210 |
cert = self.certificate_service.get_certificate(v)
|
180 |
211 |
|
181 |
212 |
if cert is None:
|
|
213 |
Logger.error(f"No such certificate found 'ID = {v}'.")
|
182 |
214 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA
|
183 |
215 |
else:
|
184 |
216 |
data = self.cert_to_dict_full(cert)
|
... | ... | |
196 |
228 |
|
197 |
229 |
:rtype: CertificateListResponse
|
198 |
230 |
"""
|
|
231 |
|
|
232 |
Logger.info(f"\n\t{request.referrer}"
|
|
233 |
f"\n\t{request.method} {request.path} {request.scheme}")
|
|
234 |
|
199 |
235 |
targets = {ROOT_CA_ID, INTERMEDIATE_CA_ID, CERTIFICATE_ID} # all targets
|
200 |
236 |
issuer_id = -1
|
201 |
237 |
|
... | ... | |
207 |
243 |
try:
|
208 |
244 |
data = {FILTERING: json.loads(request.args[FILTERING])}
|
209 |
245 |
except JSONDecodeError:
|
|
246 |
Logger.error(f"The request must be JSON-formatted.")
|
210 |
247 |
return E_NOT_JSON_FORMAT, C_BAD_REQUEST
|
211 |
248 |
|
|
249 |
Logger.info(f"\n\tRequest body:"
|
|
250 |
f"\n{dict_to_string(data)}")
|
|
251 |
|
212 |
252 |
if FILTERING in data: # if the 'filtering' field exists
|
213 |
253 |
if isinstance(data[FILTERING], dict): # and it is also a 'dict'
|
214 |
254 |
if CA in data[FILTERING]: # containing 'CA'
|
... | ... | |
219 |
259 |
targets.remove(ROOT_CA_ID)
|
220 |
260 |
targets.remove(INTERMEDIATE_CA_ID)
|
221 |
261 |
else:
|
|
262 |
Logger.error(f"Invalid request, wrong parameters '{FILTERING}.{CA}'.")
|
222 |
263 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
223 |
264 |
if ISSUED_BY in data[FILTERING]: # containing 'issuedby'
|
224 |
265 |
if isinstance(data[FILTERING][ISSUED_BY], int): # which is an 'int'
|
225 |
266 |
issuer_id = data[FILTERING][ISSUED_BY] # then get its children only
|
226 |
267 |
else:
|
|
268 |
Logger.error(f"Invalid request, wrong parameters '{FILTERING}'.")
|
227 |
269 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
228 |
270 |
if issuer_id >= 0: # if filtering by an issuer
|
229 |
271 |
try:
|
230 |
272 |
children = self.certificate_service.get_certificates_issued_by(issuer_id) # get his children
|
231 |
273 |
except CertificateNotFoundException: # if id does not exist
|
|
274 |
Logger.error(f"No such certificate found 'ID = {issuer_id}'.")
|
232 |
275 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND # throw
|
233 |
276 |
|
234 |
277 |
certs = [child for child in children if child.type_id in targets]
|
... | ... | |
246 |
289 |
certs = self.certificate_service.get_certificates() # if no params, fetch everything
|
247 |
290 |
|
248 |
291 |
if certs is None:
|
|
292 |
Logger.error(f"Internal server error (unknown origin).")
|
249 |
293 |
return E_GENERAL_ERROR, C_INTERNAL_SERVER_ERROR
|
250 |
294 |
elif len(certs) == 0:
|
|
295 |
# TODO check log level
|
|
296 |
Logger.warning(f"No such certificate found (empty list).")
|
251 |
297 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA
|
252 |
298 |
else:
|
253 |
299 |
ret = []
|
254 |
300 |
for c in certs:
|
255 |
301 |
data = self.cert_to_dict_partial(c)
|
256 |
302 |
if data is None:
|
|
303 |
Logger.error(f"Internal server error (corrupted database).")
|
257 |
304 |
return E_CORRUPTED_DATABASE, C_INTERNAL_SERVER_ERROR
|
258 |
305 |
ret.append(
|
259 |
306 |
data
|
... | ... | |
270 |
317 |
|
271 |
318 |
:rtype: PemResponse
|
272 |
319 |
"""
|
|
320 |
|
|
321 |
Logger.info(f"\n\t{request.referrer}"
|
|
322 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
323 |
f"\n\tCertificate ID = {id}")
|
|
324 |
|
273 |
325 |
try:
|
274 |
326 |
v = int(id)
|
275 |
327 |
except ValueError:
|
|
328 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
276 |
329 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
277 |
330 |
|
278 |
331 |
cert = self.certificate_service.get_certificate(v)
|
279 |
332 |
|
280 |
333 |
if cert is None:
|
|
334 |
Logger.error(f"No such certificate found 'ID = {v}'.")
|
281 |
335 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA
|
282 |
336 |
|
283 |
337 |
trust_chain = self.certificate_service.get_chain_of_trust(cert.parent_id, exclude_root=False)
|
284 |
338 |
if trust_chain is None or len(trust_chain) == 0:
|
|
339 |
Logger.error(f"No such certificate found (empty list).")
|
285 |
340 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA
|
286 |
341 |
|
287 |
342 |
return {"success": True, "data": trust_chain[-1].pem_data}, C_SUCCESS
|
... | ... | |
297 |
352 |
:rtype: PemResponse
|
298 |
353 |
"""
|
299 |
354 |
|
|
355 |
Logger.info(f"\n\t{request.referrer}"
|
|
356 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
357 |
f"\n\tCertificate ID = {id}")
|
|
358 |
|
300 |
359 |
try:
|
301 |
360 |
v = int(id)
|
302 |
361 |
except ValueError:
|
|
362 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
303 |
363 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
304 |
364 |
|
305 |
365 |
cert = self.certificate_service.get_certificate(v)
|
306 |
366 |
|
307 |
367 |
if cert is None:
|
|
368 |
Logger.error(f"No such certificate found 'ID = {v}'.")
|
308 |
369 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA
|
309 |
370 |
|
310 |
371 |
if cert.parent_id is None:
|
|
372 |
Logger.error(f"Parent ID is empty in certificate 'ID = {v}'.")
|
311 |
373 |
return E_NO_CERTIFICATES_FOUND, C_NO_DATA
|
312 |
374 |
|
313 |
375 |
trust_chain = self.certificate_service.get_chain_of_trust(cert.parent_id)
|
... | ... | |
329 |
391 |
|
330 |
392 |
:rtype: SuccessResponse | ErrorResponse (see OpenAPI definition)
|
331 |
393 |
"""
|
332 |
|
required_keys = {STATUS} # required keys
|
333 |
394 |
|
334 |
|
# try to parse certificate identifier -> if it is not int return error 400
|
335 |
|
try:
|
336 |
|
identifier = int(id)
|
337 |
|
except ValueError:
|
338 |
|
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
|
395 |
Logger.info(f"\n\t{request.referrer}"
|
|
396 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
397 |
f"\n\tCertificate ID = {id}")
|
|
398 |
|
|
399 |
required_keys = {STATUS} # required keys
|
339 |
400 |
|
340 |
401 |
# check if the request contains a JSON body
|
341 |
402 |
if request.is_json:
|
342 |
403 |
request_body = request.get_json()
|
|
404 |
|
|
405 |
Logger.info(f"\n\tRequest body:"
|
|
406 |
f"\n{dict_to_string(request_body)}")
|
|
407 |
|
|
408 |
# try to parse certificate identifier -> if it is not int return error 400
|
|
409 |
try:
|
|
410 |
identifier = int(id)
|
|
411 |
except ValueError:
|
|
412 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
|
413 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
|
414 |
|
343 |
415 |
# verify that all required keys are present
|
344 |
416 |
if not all(k in request_body for k in required_keys):
|
|
417 |
Logger.error(f"Invalid request, missing parameters.")
|
345 |
418 |
return E_MISSING_PARAMETERS, C_BAD_REQUEST
|
346 |
419 |
|
347 |
420 |
# get status and reason from the request
|
... | ... | |
352 |
425 |
self.certificate_service.set_certificate_revocation_status(identifier, status, reason)
|
353 |
426 |
except (RevocationReasonInvalidException, CertificateStatusInvalidException):
|
354 |
427 |
# these exceptions are thrown in case invalid status or revocation reason is passed to the controller
|
|
428 |
Logger.error(f"Invalid request, wrong parameters.")
|
355 |
429 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
356 |
430 |
except CertificateAlreadyRevokedException:
|
|
431 |
Logger.error(f"Certificate is already revoked 'ID = {identifier}'.")
|
357 |
432 |
return E_NO_CERTIFICATE_ALREADY_REVOKED, C_BAD_REQUEST
|
358 |
433 |
except CertificateNotFoundException:
|
|
434 |
Logger.error(f"No such certificate found 'ID = {identifier}'.")
|
359 |
435 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND
|
360 |
436 |
return {"success": True,
|
361 |
437 |
"data": "Certificate status updated successfully."}, C_SUCCESS
|
362 |
438 |
# throw an error in case the request does not contain a json body
|
363 |
439 |
else:
|
|
440 |
Logger.error(f"The request must be JSON-formatted.")
|
364 |
441 |
return E_NOT_JSON_FORMAT, C_BAD_REQUEST
|
365 |
442 |
|
366 |
443 |
def cert_to_dict_partial(self, c):
|
... | ... | |
369 |
446 |
:param c: target cert
|
370 |
447 |
:return: certificate dict (compliant with some parts of the REST API)
|
371 |
448 |
"""
|
|
449 |
|
|
450 |
# TODO check log
|
|
451 |
Logger.debug(f"Function launched.")
|
|
452 |
|
372 |
453 |
c_issuer = self.certificate_service.get_certificate(c.parent_id)
|
373 |
454 |
if c_issuer is None:
|
374 |
455 |
return None
|
... | ... | |
392 |
473 |
:param c: target cert
|
393 |
474 |
:return: certificate dict (compliant with some parts of the REST API)
|
394 |
475 |
"""
|
|
476 |
|
|
477 |
Logger.info(f"Function launched.")
|
|
478 |
|
395 |
479 |
subj = self.certificate_service.get_subject_from_certificate(c)
|
396 |
480 |
c_issuer = self.certificate_service.get_certificate(c.parent_id)
|
397 |
481 |
if c_issuer is None:
|
... | ... | |
415 |
499 |
:rtype: PemResponse
|
416 |
500 |
"""
|
417 |
501 |
|
|
502 |
Logger.info(f"\n\t{request.referrer}"
|
|
503 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
504 |
f"\n\tCertificate ID = {id}")
|
|
505 |
|
418 |
506 |
# try to parse the supplied ID
|
419 |
507 |
try:
|
420 |
508 |
v = int(id)
|
421 |
509 |
except ValueError:
|
|
510 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
422 |
511 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
423 |
512 |
|
424 |
513 |
# find a certificate using the given ID
|
425 |
514 |
cert = self.certificate_service.get_certificate(v)
|
426 |
515 |
|
427 |
516 |
if cert is None:
|
|
517 |
Logger.error(f"No such certificate found 'ID = {v}'.")
|
428 |
518 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND
|
429 |
519 |
else:
|
430 |
520 |
# certificate exists, fetch it's private key
|
431 |
521 |
private_key = self.key_service.get_key(cert.private_key_id)
|
432 |
522 |
if cert is None:
|
|
523 |
Logger.error(f"Internal server error (certificate's private key cannot be found).")
|
433 |
524 |
return E_NO_CERT_PRIVATE_KEY_FOUND, C_INTERNAL_SERVER_ERROR
|
434 |
525 |
else:
|
435 |
526 |
return {"success": True, "data": private_key.private_key}, C_SUCCESS
|
... | ... | |
444 |
535 |
:rtype: PemResponse
|
445 |
536 |
"""
|
446 |
537 |
|
|
538 |
Logger.info(f"\n\t{request.referrer}"
|
|
539 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
540 |
f"\n\tCertificate ID = {id}")
|
|
541 |
|
447 |
542 |
# try to parse the supplied ID
|
448 |
543 |
try:
|
449 |
544 |
v = int(id)
|
450 |
545 |
except ValueError:
|
|
546 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
451 |
547 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
452 |
548 |
|
453 |
549 |
# find a certificate using the given ID
|
454 |
550 |
cert = self.certificate_service.get_certificate(v)
|
455 |
551 |
|
456 |
552 |
if cert is None:
|
|
553 |
Logger.error(f"No such certificate found 'ID = {v}'.")
|
457 |
554 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND
|
458 |
555 |
else:
|
459 |
556 |
return {"success": True, "data": self.certificate_service.get_public_key_from_certificate(cert)}, C_SUCCESS
|
... | ... | |
464 |
561 |
:param id: target certificate ID
|
465 |
562 |
:rtype: DeleteResponse
|
466 |
563 |
"""
|
|
564 |
|
|
565 |
Logger.info(f"\n\t{request.referrer}"
|
|
566 |
f"\n\t{request.method} {request.path} {request.scheme}"
|
|
567 |
f"\n\tCertificate ID = {id}")
|
|
568 |
|
467 |
569 |
try:
|
468 |
570 |
v = int(id)
|
469 |
571 |
except ValueError:
|
|
572 |
Logger.error(f"Invalid request, wrong parameters 'id'[{id}].")
|
470 |
573 |
return E_WRONG_PARAMETERS, C_BAD_REQUEST
|
471 |
574 |
|
472 |
575 |
try:
|
473 |
576 |
self.certificate_service.delete_certificate(v)
|
474 |
577 |
except CertificateNotFoundException:
|
|
578 |
Logger.error(f"No such certificate found 'ID = {v}'.")
|
475 |
579 |
return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND
|
476 |
580 |
except DatabaseException:
|
|
581 |
Logger.error(f"Internal server error (corrupted database).")
|
477 |
582 |
return E_CORRUPTED_DATABASE, C_INTERNAL_SERVER_ERROR
|
478 |
583 |
except CertificateStatusInvalidException or RevocationReasonInvalidException or UnknownException:
|
|
584 |
Logger.error(f"Internal server error (unknown origin).")
|
479 |
585 |
return E_GENERAL_ERROR, C_INTERNAL_SERVER_ERROR
|
480 |
586 |
|
481 |
587 |
return {"success": True, "data": "The certificate and its descendants have been successfully deleted."}
|
Re #8570 - Messages logging