def get_smart_cards_sessions(): ''' Check for connected smart card Returns: a session list of connected smart cards ''' # getting a smart card session return SignatureUtils().fetch_smart_card_sessions()
def session_login(sessions, pin): ''' Attempt to login on connected smart cards Param: sessions: connected smart card slots pin: user pin Returns: logged in session ''' # login on the session return SignatureUtils().user_login(sessions, pin)
def sign(datau, session, cert, cert_value, hashalgo, attrs=True, signed_value=None): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now() x509 = Certificate.load(cert_value) certificates = [] certificates.append(x509) cert_value_digest = bytes( session.digest(cert_value, Mechanism(LowLevel.CKM_SHA256))) MyLogger().my_logger().info('building signed attributes...') signer = { 'version': 'v1', 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': x509.issuer, 'serial_number': x509.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': hashalgo}), 'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': 'rsassa_pkcs1v15'}), 'signature': signed_value, } if attrs: signer['signed_attrs'] = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data', ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value, ), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('signing_time'), 'values': (cms.Time({'utc_time': core.UTCTime(signed_time)}), ) }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('1.2.840.113549.1.9.16.2.47'), 'values': (tsp.SigningCertificateV2({ 'certs': (tsp.ESSCertIDv2({ 'hash_algorithm': algos.DigestAlgorithm({ 'algorithm': hashalgo, 'parameters': None }), 'cert_hash': cert_value_digest, }), ), }), ) }), ] config = { 'version': 'v1', 'digest_algorithms': cms.DigestAlgorithms((algos.DigestAlgorithm({'algorithm': hashalgo}), )), 'encap_content_info': { 'content_type': 'data', }, 'certificates': certificates, # 'crls': [], 'signer_infos': [ signer, ], } datas = cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': cms.SignedData(config), }) if attrs: tosign = datas['content']['signer_infos'][0]['signed_attrs'].dump() tosign = b'\x31' + tosign[1:] else: tosign = datau MyLogger().my_logger().info('signed attributes ready') # fetching private key from smart card priv_key = SignatureUtils.fetch_private_key(session, cert) mechanism = Mechanism(LowLevel.CKM_SHA256_RSA_PKCS, None) MyLogger().my_logger().info('signing...') # signing bytes to be signed signature = session.sign(priv_key, tosign, mechanism) datas['content']['signer_infos'][0]['signature'] = bytes(signature) return datas.dump()
def sign_pdf(file_path, open_session, user_cf, sig_attributes): ''' Return a signed pdf file path The file name will be the same with (firmato) before the extension and .pdf at the end The path will be the same Param: file_path: complete or relative path of the file to sign open_session: logged in session (from login_attempt()) ''' # fetching smart card certificate certificate = SignatureUtils.fetch_certificate(open_session) # getting certificate value certificate_value = SignatureUtils.get_certificate_value( open_session, certificate) # check for signer identity # if user_cf == "X" * 15, avoid this check if user_cf != "X" * 15: # only for REST calls DigiSignLib()._check_certificate_owner(certificate_value, user_cf) # check for certificate time validity DigiSignLib()._check_certificate_validity(certificate_value) MyLogger().my_logger().info(f"reading pdf file {file_path}") datau = open(file_path, 'rb').read() datas = pdf_builder.sign(datau, open_session, certificate, certificate_value, 'sha256', sig_attributes) signed_file_path = DigiSignLib().get_signed_files_path( file_path, 'pdf') MyLogger().my_logger().info(f"saving output to {signed_file_path}") with open(signed_file_path, 'wb') as fp: fp.write(datau) fp.write(datas) MyLogger().my_logger().info( f"verifying pdf signatures of {signed_file_path}") try: new_data = open(signed_file_path, 'rb').read() results = verify(new_data, [certificate_value]) for key, res in enumerate(results, start=1): print('Signature %d: ' % key, res) MyLogger().my_logger().info(f"Signature {key}: {res}") if not res['hashok?']: raise PdfVerificationError( f"Hash verification of Signature {key} is failed.") if not res['signatureok?']: raise PdfVerificationError( f"Signature verification of Signature {key} is failed." ) if not res['certok?']: # TODO verify certificates MyLogger().my_logger().error( f"Certificate verification of Signature {key} is failed." ) except: MyLogger().my_logger().error( f"Error during verification of Signature {key}:") raise return signed_file_path
def session_close(session): ''' Close smart card `session` ''' # session close SignatureUtils().close_session(session)
def session_logout(session): ''' User logout from session ''' # logout from the session SignatureUtils().user_logout(session)
def sign_p7m(file_path, open_session, user_cf, sig_attrs): ''' Return a signed p7m file path The file name will be the same with (firmato) before the extension and .p7m at the end The path will be the same Param: file_path: complete or relative path of the file to sign open_session: logged in session (from login_attempt()) ''' # fetching sig type sig_type = sig_attrs['p7m_sig_type'] # fetching file content file_content = DigiSignLib().get_file_content(file_path) # check existing signatures p7m_attrs = P7mAttributes(b'', b'', b'') mime = MimeTypes().guess_type(file_path)[0] if mime == 'application/pkcs7': info = cms.ContentInfo.load(file_content) # retrieving existing signatures attributes signed_data = info['content'] p7m_attrs.algos = signed_data['digest_algorithms'].contents p7m_attrs.certificates = signed_data['certificates'].contents # if sig_type == 'parallel': p7m_attrs.signer_infos = signed_data['signer_infos'].contents file_content = signed_data['encap_content_info'].native[ 'content'] # hashing file content file_content_digest = SignatureUtils().digest(open_session, file_content) # fetching smart card certificate certificate = SignatureUtils().fetch_certificate(open_session) # getting certificate value certificate_value = SignatureUtils().get_certificate_value( open_session, certificate) # hashing certificate value certificate_value_digest = SignatureUtils().digest( open_session, certificate_value) # check for signer identity # if user_cf == "X" * 15, avoid this check if user_cf != "X" * 15: # only for REST calls DigiSignLib()._check_certificate_owner(certificate_value, user_cf) # check for certificate time validity DigiSignLib()._check_certificate_validity(certificate_value) # getting signed attributes p7m field try: signed_attributes = P7mEncoder().encode_signed_attributes( file_content_digest, certificate_value_digest) except: raise P7mCreationError("Exception on encoding signed attributes") # getting bytes to be signed try: bytes_to_sign = P7mEncoder().bytes_to_sign( file_content_digest, certificate_value_digest) except: raise P7mCreationError("Exception on encoding bytes to sign") # fetching private key from smart card privKey = SignatureUtils().fetch_private_key(open_session, certificate) # signing bytes to be signed signed_attributes_signed = SignatureUtils().signature( open_session, privKey, bytes_to_sign) # getting issuer from certificate issuer = SignatureUtils().get_certificate_issuer( open_session, certificate) # getting serial number from certificate serial_number = SignatureUtils().get_certificate_serial_number( open_session, certificate) # getting signer info p7m field try: signer_info = P7mEncoder().encode_signer_info( issuer, serial_number, signed_attributes, signed_attributes_signed, p7m_attrs.signer_infos) except: raise P7mCreationError("Exception on encoding signer info") # create the p7m content try: output_content = P7mEncoder().make_a_p7m(file_content, certificate_value, signer_info, p7m_attrs) except: raise P7mCreationError("Exception on encoding p7m file content") # saves p7m to file signed_file_path = DigiSignLib().get_signed_files_path( file_path, 'p7m', sig_type) DigiSignLib().save_file_content(signed_file_path, output_content) return signed_file_path