diff --git a/src/JWS_Types.ttcn b/src/JWS_Types.ttcn index dd2cc9a95c156b176d9d3b8cae7ea17a8d69a3dd..3aaa79a4e78a27c0013b44c6e2d107d474ca1cc5 100644 --- a/src/JWS_Types.ttcn +++ b/src/JWS_Types.ttcn @@ -1,642 +1,642 @@ -/****************************************************************************** -* Copyright (c) 2020 Ericsson AB -* All rights reserved. This program and the accompanying materials -* are made available under the terms of the Eclipse Public License v2.0 -* which accompanies this distribution, and is available at -* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html -* -* Contributors: -* Gabor Szalai - initial implementation and initial documentation -******************************************************************************/ -// -// File: JWS_Types.ttcn -// Description: Type definitions for JWS, PASSporT and SHAKEN -/////////////////////////////////////////////// -module JWS_Types { - -import from JSON_Generic all; -import from TCCConversion_Functions all; -import from TCCOpenSecurity_Functions all; -import from TCCEncoding_Functions all; -import from JWS_helper all; - -function f_JWS_Sign(in JWS_Object pl_obj, - in octetstring pl_key, // The private key in PEM format - in charstring pl_passwd, // The optional password of the private key. Empty string is no password - in JWS_Serialization_Mode pl_ser_mode:=JWS_Basic_Serialization, - out JWS_Compact_unpacked pl_signed_obj -) return JWS_Sign_Result { - pl_signed_obj:={omit,omit,omit} - - if(not ispresent(pl_obj.jose_header.alg)){ - // alg is not specified - return JWS_Error - } - - pl_signed_obj:=f_JWS_Object_serialize(pl_obj,pl_ser_mode) - - select(pl_obj.jose_header.alg){ - case (pattern "[hH][sS]256"){ - var octetstring vl_sig_oct - var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha256",pl_key, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct) - if(vl_sign_res==TCCOpenSecurity_Result_OK){ - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } else { - return JWS_Error - } - } - case (pattern "[hH][sS]384"){ - var octetstring vl_sig_oct - var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha384",pl_key, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct) - if(vl_sign_res==TCCOpenSecurity_Result_OK){ - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } else { - return JWS_Error - } - } - case (pattern "[hH][sS]512"){ - var octetstring vl_sig_oct - var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha512",pl_key, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct) - if(vl_sign_res==TCCOpenSecurity_Result_OK){ - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } else { - return JWS_Error - } - } - case ( pattern "[rR][sS]256") { - var octetstring vl_sig_oct - var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA256", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - - select(vl_sign_res){ - case (DigestSign_OK){ - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } - case else { - return JWS_Error - } - } - } - case ( pattern "[rR][sS]384") { - var octetstring vl_sig_oct - var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA384", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - - select(vl_sign_res){ - case (DigestSign_OK){ - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } - case else { - return JWS_Error - } - } - } - case ( pattern "[rR][sS]512") { - var octetstring vl_sig_oct - var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA512", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - - select(vl_sign_res){ - case (DigestSign_OK){ - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } - case else { - return JWS_Error - } - } - } - case ( pattern "[eE][sS]256") { - var octetstring vl_sig_oct - var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA256", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - - select(vl_sign_res){ - case (DigestSign_OK){ - var JWS_helper_struct vl_helper:=decode_JWS_helper_struct(vl_sig_oct) - vl_sig_oct:=int2oct(vl_helper.f1,32) & int2oct(vl_helper.f2,32) - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } - case else { - return JWS_Error - } - } - } - case ( pattern "[eE][sS]384") { - var octetstring vl_sig_oct - var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA384", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - - select(vl_sign_res){ - case (DigestSign_OK){ - var JWS_helper_struct vl_helper:=decode_JWS_helper_struct(vl_sig_oct) - vl_sig_oct:=int2oct(vl_helper.f1,48) & int2oct(vl_helper.f2,48) - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } - case else { - return JWS_Error - } - } - } - case ( pattern "[eE][sS]512") { - var octetstring vl_sig_oct - var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA512", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - - select(vl_sign_res){ - case (DigestSign_OK){ - var JWS_helper_struct vl_helper:=decode_JWS_helper_struct(vl_sig_oct) - vl_sig_oct:=int2oct(vl_helper.f1,66) & int2oct(vl_helper.f2,66) - pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) - return JWS_Sign_OK - } - case else { - return JWS_Error - } - } - } - case else { - // The selected alg is not implemented - return JWS_Not_Supported - } - } - - - return JWS_Error -} - -function f_JWS_Sign_verify(in JWS_Compact_unpacked pl_signed_obj, - in octetstring pl_key, // The public key in PEM format - in charstring pl_passwd // The optional password of the key. Empty string is no password -) return JWS_Sign_Result { - - var JWS_Object vl_jws_obj - var integer vl_res:=f_JWS_Object_unserialize(pl_signed_obj,vl_jws_obj) - - if(vl_res !=0) { - // Can't unpack the received data - return JWS_Error - } - - if(not ispresent(vl_jws_obj.jose_header.alg)){ - // alg is not specified - return JWS_Error - } - - if(not ispresent(pl_signed_obj.jws_signature)){ - // signature is missing - return JWS_Error - } - - select(vl_jws_obj.jose_header.alg){ - case (pattern "[hH][sS]256"){ - var octetstring vl_sig_oct - var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha256",pl_key, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct) - if(vl_sign_res!=TCCOpenSecurity_Result_OK){ - return JWS_Error - } - var octetstring vl_recv_sig:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url) - if(vl_recv_sig==vl_sig_oct) { - return JWS_Sign_OK - } else { - return JWS_Sign_Verification_Failed - } - } - case (pattern "[hH][sS]384"){ - var octetstring vl_sig_oct - var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha384",pl_key, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct) - if(vl_sign_res!=TCCOpenSecurity_Result_OK){ - return JWS_Error - } - var octetstring vl_recv_sig:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url) - if(vl_recv_sig==vl_sig_oct) { - return JWS_Sign_OK - } else { - return JWS_Sign_Verification_Failed - } - } - case (pattern "[hH][sS]512"){ - var octetstring vl_sig_oct - var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha512",pl_key, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct) - if(vl_sign_res!=TCCOpenSecurity_Result_OK){ - return JWS_Error - } - var octetstring vl_recv_sig:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url) - if(vl_recv_sig==vl_sig_oct) { - return JWS_Sign_OK - } else { - return JWS_Sign_Verification_Failed - } - } - case ( pattern "[rR][sS]256") { - var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); - var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA256", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - select(vl_verify_res){ - case (DigestSign_OK){ - return JWS_Sign_OK - } - case (DigestSign_Verification_Failed) { - return JWS_Sign_Verification_Failed - } - case else { - return JWS_Error - } - } - } - case ( pattern "[rR][sS]384") { - var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); - var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA384", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - select(vl_verify_res){ - case (DigestSign_OK){ - return JWS_Sign_OK - } - case (DigestSign_Verification_Failed) { - return JWS_Sign_Verification_Failed - } - case else { - return JWS_Error - } - } - } - case ( pattern "[rR][sS]512") { - var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); - var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA512", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - select(vl_verify_res){ - case (DigestSign_OK){ - return JWS_Sign_OK - } - case (DigestSign_Verification_Failed) { - return JWS_Sign_Verification_Failed - } - case else { - return JWS_Error - } - } - } - case ( pattern "[eE][sS]256") { - var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); - if(lengthof(vl_sig_oct)!=64){ - // Wrong signature length - return JWS_Error - } - var JWS_helper_struct vl_helper:={oct2int(substr(vl_sig_oct,0,32)),oct2int(substr(vl_sig_oct,32,32))} - vl_sig_oct:=encode_JWS_helper_struct(vl_helper); - var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA256", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - select(vl_verify_res){ - case (DigestSign_OK){ - return JWS_Sign_OK - } - case (DigestSign_Verification_Failed) { - return JWS_Sign_Verification_Failed - } - case else { - return JWS_Error - } - } - } - case ( pattern "[eE][sS]384") { - var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); - if(lengthof(vl_sig_oct)!=96){ - // Wrong signature length - return JWS_Error - } - var JWS_helper_struct vl_helper:={oct2int(substr(vl_sig_oct,0,48)),oct2int(substr(vl_sig_oct,48,48))} - vl_sig_oct:=encode_JWS_helper_struct(vl_helper); - var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA384", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - select(vl_verify_res){ - case (DigestSign_OK){ - return JWS_Sign_OK - } - case (DigestSign_Verification_Failed) { - return JWS_Sign_Verification_Failed - } - case else { - return JWS_Error - } - } - } - case ( pattern "[eE][sS]512") { - var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); - if(lengthof(vl_sig_oct)!=132){ - // Wrong signature length - return JWS_Error - } - var JWS_helper_struct vl_helper:={oct2int(substr(vl_sig_oct,0,66)),oct2int(substr(vl_sig_oct,66,66))} - vl_sig_oct:=encode_JWS_helper_struct(vl_helper); - var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA512", pl_key, pl_passwd, - char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), - vl_sig_oct - ) - select(vl_verify_res){ - case (DigestSign_OK){ - return JWS_Sign_OK - } - case (DigestSign_Verification_Failed) { - return JWS_Sign_Verification_Failed - } - case else { - return JWS_Error - } - } - } - case else { - // The selected alg is not implemented - return JWS_Not_Supported - } - } - - - - return JWS_Error -} - - -// Function to unpack and pack the JWS Compact representation (see 3.1 of RFC7515) -// into the JWS_Compact_unpacked by separating each part. - -// returns empty struct if the format of the input is invalid -function f_JWS_Unpack_Compact_Representation(in JWS_Compact_serialized pl_serialized) return JWS_Compact_unpacked { - var TCC_Conversion_ch_list vl_splitted:=f_split(pl_serialized,"."); - if(lengthof(vl_splitted)!=3){ - return {omit,omit,omit} - } - - return {vl_splitted[0],vl_splitted[1],vl_splitted[2]} -} - -function f_JWS_Pack_Compact_Representation(in JWS_Compact_unpacked pl_unpacked) return JWS_Compact_serialized { - var JWS_Compact_serialized ret_val:="" - if(ispresent(pl_unpacked.protected_header)) { - ret_val:=ret_val & pl_unpacked.protected_header - } - ret_val:=ret_val & "." - if(ispresent(pl_unpacked.jws_payload)) { - ret_val:=ret_val & pl_unpacked.jws_payload - } - ret_val:=ret_val & "." - if(ispresent(pl_unpacked.jws_signature)) { - ret_val:=ret_val & pl_unpacked.jws_signature - } - return ret_val -} - -// Converts the JWS object into JWS Compact Serialization format. -// serialize -> Converts the JOSE header and payload to JSON, and use the BASE64URL encoding -// unserialize -> Base64 decode the payload and the JOSE header and extract the values from the JSON - -function f_JWS_Object_serialize(in JWS_Object pl_obj,in JWS_Serialization_Mode pl_ser_mode:=JWS_Basic_Serialization) return JWS_Compact_unpacked { - var JWS_Compact_unpacked vl_ret:={omit,omit,omit} - - var JWS_JSON_Object vl_jose_json:={} - - if(ispresent(pl_obj.jose_header.alg)){ - vl_jose_json[lengthof(vl_jose_json)]:={"alg",{JSON_string:=pl_obj.jose_header.alg}} - } - if(ispresent(pl_obj.jose_header.ppt)){ - vl_jose_json[lengthof(vl_jose_json)]:={"ppt",{JSON_string:=pl_obj.jose_header.ppt}} - } - if(ispresent(pl_obj.jose_header.typ)){ - vl_jose_json[lengthof(vl_jose_json)]:={"typ",{JSON_string:=pl_obj.jose_header.typ}} - } - if(ispresent(pl_obj.jose_header.x5u)){ - vl_jose_json[lengthof(vl_jose_json)]:={"x5u",{JSON_string:=pl_obj.jose_header.x5u}} - } - if(ispresent(pl_obj.jose_header.additional_headers)){ - vl_jose_json := vl_jose_json & pl_obj.jose_header.additional_headers - } - - if(pl_ser_mode == JWS_Deterministic_Serialization){ - vl_jose_json := f_sort_JWS_JSON_Object(vl_jose_json) - } - - vl_ret.protected_header:=enc_Base64(f_enc_JSON({JSON_object:=vl_jose_json}),Base64_Url) - - if(ischosen(pl_obj.jws_payload.json_claim)){ - if(pl_ser_mode == JWS_Deterministic_Serialization){ - vl_ret.jws_payload:=enc_Base64(f_enc_JSON({JSON_object:=f_sort_JWS_JSON_Object(pl_obj.jws_payload.json_claim)}),Base64_Url) - } else { - vl_ret.jws_payload:=enc_Base64(f_enc_JSON({JSON_object:=pl_obj.jws_payload.json_claim}),Base64_Url) - } - } else { - vl_ret.jws_payload:=enc_Base64(pl_obj.jws_payload.generic_payload,Base64_Url) - } - - return vl_ret -} - -function f_JWS_Object_unserialize(in JWS_Compact_unpacked pl_comp, out JWS_Object pl_obj) return integer { // 0 - OK, 1 - Fail - // Initialize the out value - pl_obj.jose_header:={omit,omit,omit,omit,omit} // empty header - pl_obj.jws_payload:={generic_payload:=''O} // empty body - - if(ispresent(pl_comp.protected_header)){ // Decode the header - var octetstring vl_jose_oct:=dec_Base64(pl_comp.protected_header,Base64_Url) - var JSON_generic_val vl_jose_json - var integer vl_dec_res:=f_dec_JSON(vl_jose_oct,vl_jose_json) - if(vl_dec_res == 0 and ischosen(vl_jose_json.JSON_object)){ - // The protected header looks like a JSON object - var integer vl_i:=0 - for(vl_i:=0;vl_i<lengthof(vl_jose_json.JSON_object);vl_i:=vl_i+1){ - select(vl_jose_json.JSON_object[vl_i].key){ - case ("alg"){ - if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ - pl_obj.jose_header.alg:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) - } else { - // The alg should be a string - return 1; - } - } - case ("ppt"){ - if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ - pl_obj.jose_header.ppt:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) - } else { - // The ppt should be a string - return 1; - } - } - case ("typ"){ - if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ - pl_obj.jose_header.typ:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) - } else { - // The typ should be a string - return 1; - } - } - case ("x5u"){ - if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ - pl_obj.jose_header.x5u:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) - } else { - // The x5u should be a string - return 1; - } - } - case else{ - if(not ispresent(pl_obj.jose_header.additional_headers)){ - pl_obj.jose_header.additional_headers:={} - } - pl_obj.jose_header.additional_headers[lengthof(pl_obj.jose_header.additional_headers)]:=vl_jose_json.JSON_object[vl_i] - } - } - } - } else { - // JOSE header is not a JSON object - return 1; - } - } - - if(ispresent(pl_comp.jws_payload)){ - var octetstring vl_payload_oct:=dec_Base64(pl_comp.jws_payload,Base64_Url) - var JSON_generic_val vl_payload_json - var integer vl_dec_res:=f_dec_JSON(vl_payload_oct,vl_payload_json) - if(vl_dec_res == 0 and ischosen(vl_payload_json.JSON_object)){ - // The payload looks like a JSON object - pl_obj.jws_payload.json_claim:=vl_payload_json.JSON_object - } else { - // Generic payload - pl_obj.jws_payload.generic_payload:=vl_payload_oct - } - } - return 0 -} -// Function to encode and decode the JWS JSON serialization format as defined in Chapter 7.2 of RFC7515 - -external function f_enc_JWS_JSON_Serialization(in JWS_JSON_Serialization pdu) return octetstring -with { extension "prototype(convert) encode(JSON)" } - -external function f_dec_JWS_JSON_Serialization(in octetstring stream, out JWS_JSON_Serialization pdu) return integer -with { extension "prototype(backtrack) decode(JSON)" } - - - -// Helper functions, do not use directly -external function f_sort_JWS_JSON_Object(in JWS_JSON_Object pl_unsorted) return JWS_JSON_Object - - -external function decode_JWS_helper_struct(in octetstring os) return JWS_helper_struct -with { extension "prototype(convert) decode(BER:BER_ACCEPT_ALL)" } - -external function encode_JWS_helper_struct(in JWS_helper_struct pdu) return octetstring -with { extension "prototype(convert) encode(BER:BER_ENCODE_DER)" } - - -type JSON_generic_val.JSON_object JWS_JSON_Object - -// The result of the signing or the signiture verification -type enumerated JWS_Sign_Result{ JWS_Sign_OK, // Signed or the signiture is valid - JWS_Sign_Verification_Failed, // Signiture verification failed - JWS_Not_Supported, // The selected alg is not supported - JWS_Error // Something went wrong -} - -type enumerated JWS_Serialization_Mode { JWS_Basic_Serialization, // The JOSE header and the JSON body is encoded as is without any ordering and white space removal - JWS_Deterministic_Serialization // See chapter 9 of RFC 8225 - } - -// The representation of the JOSE header as defined in RFC 7515 -type record JWS_JOSE_Header{ - charstring alg optional, - charstring ppt optional, - charstring typ optional, - charstring x5u optional, - JWS_JSON_Object additional_headers optional // The other headers goes there -} - -// JWS payload representation -type union JWS_Claim_Payload{ - JWS_JSON_Object json_claim, // The payload is a JSON object/claim - octetstring generic_payload // Generic payload. It can be whatever -} - -// The JWS object to be signed -type record JWS_Object{ - JWS_JOSE_Header jose_header, - JWS_Claim_Payload jws_payload -} - -// The unpacked form of the JWS Compact representation (see 3.1 of RFC7515) -type record JWS_Compact_unpacked{ - charstring protected_header optional, // BASE64URL(UTF8(JWS Protected Header)) - charstring jws_payload optional, // BASE64URL(JWS Payload) - charstring jws_signature optional // BASE64URL(JWS Signature) -} - -type charstring JWS_Compact_serialized - - -// Data type for the JWS JSON Serialization Chapter 7.2 of RFC7515 -// Support both the general and flattened syntax -type set JWS_JSON_Serialization{ - charstring jws_payload, - JSON_generic_val unprotected_header optional, - charstring protected_header optional, - charstring jws_signature optional, - JWS_JSON_Signatures_list signatures optional -} with { - variant (jws_payload) "name as 'payload'" - variant (jws_signature) "name as 'signature'" - variant (unprotected_header) "name as 'header'" - variant (protected_header) "name as 'protected'" -} - - -type record of JWS_JSON_Signatures JWS_JSON_Signatures_list - -type set JWS_JSON_Signatures{ - JSON_generic_val unprotected_header optional, - charstring protected_header optional, - charstring jws_signature optional -} with { - variant (jws_signature) "name as 'signature'" - variant (unprotected_header) "name as 'header'" - variant (protected_header) "name as 'protected'" -} - -} with { - encode "JSON" -} +/****************************************************************************** +* Copyright (c) 2020-2023 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +* +* Contributors: +* Gabor Szalai - initial implementation and initial documentation +******************************************************************************/ +// +// File: JWS_Types.ttcn +// Description: Type definitions for JWS, PASSporT and SHAKEN +/////////////////////////////////////////////// +module JWS_Types { + +import from JSON_Generic all; +import from TCCConversion_Functions all; +import from TCCOpenSecurity_Functions all; +import from TCCEncoding_Functions all; +import from JWS_helper all; + +function f_JWS_Sign(in JWS_Object pl_obj, + in octetstring pl_key, // The private key in PEM format + in charstring pl_passwd, // The optional password of the private key. Empty string is no password + in JWS_Serialization_Mode pl_ser_mode:=JWS_Basic_Serialization, + out JWS_Compact_unpacked pl_signed_obj +) return JWS_Sign_Result { + pl_signed_obj:={omit,omit,omit} + + if(not ispresent(pl_obj.jose_header.alg)){ + // alg is not specified + return JWS_Error + } + + pl_signed_obj:=f_JWS_Object_serialize(pl_obj,pl_ser_mode) + + select(pl_obj.jose_header.alg){ + case (pattern "[hH][sS]256"){ + var octetstring vl_sig_oct + var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha256",pl_key, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct) + if(vl_sign_res==TCCOpenSecurity_Result_OK){ + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } else { + return JWS_Error + } + } + case (pattern "[hH][sS]384"){ + var octetstring vl_sig_oct + var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha384",pl_key, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct) + if(vl_sign_res==TCCOpenSecurity_Result_OK){ + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } else { + return JWS_Error + } + } + case (pattern "[hH][sS]512"){ + var octetstring vl_sig_oct + var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha512",pl_key, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct) + if(vl_sign_res==TCCOpenSecurity_Result_OK){ + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } else { + return JWS_Error + } + } + case ( pattern "[rR][sS]256") { + var octetstring vl_sig_oct + var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA256", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + + select(vl_sign_res){ + case (DigestSign_OK){ + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } + case else { + return JWS_Error + } + } + } + case ( pattern "[rR][sS]384") { + var octetstring vl_sig_oct + var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA384", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + + select(vl_sign_res){ + case (DigestSign_OK){ + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } + case else { + return JWS_Error + } + } + } + case ( pattern "[rR][sS]512") { + var octetstring vl_sig_oct + var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA512", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + + select(vl_sign_res){ + case (DigestSign_OK){ + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } + case else { + return JWS_Error + } + } + } + case ( pattern "[eE][sS]256") { + var octetstring vl_sig_oct + var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA256", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + + select(vl_sign_res){ + case (DigestSign_OK){ + var JWS_helper_struct vl_helper:=decode_JWS_helper_struct(vl_sig_oct) + vl_sig_oct:=int2oct(vl_helper.f1,32) & int2oct(vl_helper.f2,32) + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } + case else { + return JWS_Error + } + } + } + case ( pattern "[eE][sS]384") { + var octetstring vl_sig_oct + var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA384", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + + select(vl_sign_res){ + case (DigestSign_OK){ + var JWS_helper_struct vl_helper:=decode_JWS_helper_struct(vl_sig_oct) + vl_sig_oct:=int2oct(vl_helper.f1,48) & int2oct(vl_helper.f2,48) + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } + case else { + return JWS_Error + } + } + } + case ( pattern "[eE][sS]512") { + var octetstring vl_sig_oct + var DigestSign_Result vl_sign_res:=f_DigestSign_data( "SHA512", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + + select(vl_sign_res){ + case (DigestSign_OK){ + var JWS_helper_struct vl_helper:=decode_JWS_helper_struct(vl_sig_oct) + vl_sig_oct:=int2oct(vl_helper.f1,66) & int2oct(vl_helper.f2,66) + pl_signed_obj.jws_signature:=enc_Base64(vl_sig_oct,Base64_Url) + return JWS_Sign_OK + } + case else { + return JWS_Error + } + } + } + case else { + // The selected alg is not implemented + return JWS_Not_Supported + } + } + + + return JWS_Error +} + +function f_JWS_Sign_verify(in JWS_Compact_unpacked pl_signed_obj, + in octetstring pl_key, // The public key in PEM format + in charstring pl_passwd // The optional password of the key. Empty string is no password +) return JWS_Sign_Result { + + var JWS_Object vl_jws_obj + var integer vl_res:=f_JWS_Object_unserialize(pl_signed_obj,vl_jws_obj) + + if(vl_res !=0) { + // Can't unpack the received data + return JWS_Error + } + + if(not ispresent(vl_jws_obj.jose_header.alg)){ + // alg is not specified + return JWS_Error + } + + if(not ispresent(pl_signed_obj.jws_signature)){ + // signature is missing + return JWS_Error + } + + select(vl_jws_obj.jose_header.alg){ + case (pattern "[hH][sS]256"){ + var octetstring vl_sig_oct + var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha256",pl_key, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct) + if(vl_sign_res!=TCCOpenSecurity_Result_OK){ + return JWS_Error + } + var octetstring vl_recv_sig:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url) + if(vl_recv_sig==vl_sig_oct) { + return JWS_Sign_OK + } else { + return JWS_Sign_Verification_Failed + } + } + case (pattern "[hH][sS]384"){ + var octetstring vl_sig_oct + var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha384",pl_key, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct) + if(vl_sign_res!=TCCOpenSecurity_Result_OK){ + return JWS_Error + } + var octetstring vl_recv_sig:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url) + if(vl_recv_sig==vl_sig_oct) { + return JWS_Sign_OK + } else { + return JWS_Sign_Verification_Failed + } + } + case (pattern "[hH][sS]512"){ + var octetstring vl_sig_oct + var TCCOpenSecurity_Result vl_sign_res:=f_HMAC_data("sha512",pl_key, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct) + if(vl_sign_res!=TCCOpenSecurity_Result_OK){ + return JWS_Error + } + var octetstring vl_recv_sig:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url) + if(vl_recv_sig==vl_sig_oct) { + return JWS_Sign_OK + } else { + return JWS_Sign_Verification_Failed + } + } + case ( pattern "[rR][sS]256") { + var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); + var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA256", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + select(vl_verify_res){ + case (DigestSign_OK){ + return JWS_Sign_OK + } + case (DigestSign_Verification_Failed) { + return JWS_Sign_Verification_Failed + } + case else { + return JWS_Error + } + } + } + case ( pattern "[rR][sS]384") { + var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); + var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA384", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + select(vl_verify_res){ + case (DigestSign_OK){ + return JWS_Sign_OK + } + case (DigestSign_Verification_Failed) { + return JWS_Sign_Verification_Failed + } + case else { + return JWS_Error + } + } + } + case ( pattern "[rR][sS]512") { + var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); + var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA512", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + select(vl_verify_res){ + case (DigestSign_OK){ + return JWS_Sign_OK + } + case (DigestSign_Verification_Failed) { + return JWS_Sign_Verification_Failed + } + case else { + return JWS_Error + } + } + } + case ( pattern "[eE][sS]256") { + var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); + if(lengthof(vl_sig_oct)!=64){ + // Wrong signature length + return JWS_Error + } + var JWS_helper_struct vl_helper:={oct2int(substr(vl_sig_oct,0,32)),oct2int(substr(vl_sig_oct,32,32))} + vl_sig_oct:=encode_JWS_helper_struct(vl_helper); + var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA256", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + select(vl_verify_res){ + case (DigestSign_OK){ + return JWS_Sign_OK + } + case (DigestSign_Verification_Failed) { + return JWS_Sign_Verification_Failed + } + case else { + return JWS_Error + } + } + } + case ( pattern "[eE][sS]384") { + var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); + if(lengthof(vl_sig_oct)!=96){ + // Wrong signature length + return JWS_Error + } + var JWS_helper_struct vl_helper:={oct2int(substr(vl_sig_oct,0,48)),oct2int(substr(vl_sig_oct,48,48))} + vl_sig_oct:=encode_JWS_helper_struct(vl_helper); + var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA384", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + select(vl_verify_res){ + case (DigestSign_OK){ + return JWS_Sign_OK + } + case (DigestSign_Verification_Failed) { + return JWS_Sign_Verification_Failed + } + case else { + return JWS_Error + } + } + } + case ( pattern "[eE][sS]512") { + var octetstring vl_sig_oct:=dec_Base64(pl_signed_obj.jws_signature,Base64_Url); + if(lengthof(vl_sig_oct)!=132){ + // Wrong signature length + return JWS_Error + } + var JWS_helper_struct vl_helper:={oct2int(substr(vl_sig_oct,0,66)),oct2int(substr(vl_sig_oct,66,66))} + vl_sig_oct:=encode_JWS_helper_struct(vl_helper); + var DigestSign_Result vl_verify_res:=f_DigestSign_Verify_data( "SHA512", pl_key, pl_passwd, + char2oct(pl_signed_obj.protected_header) & char2oct(".") & char2oct(pl_signed_obj.jws_payload), + vl_sig_oct + ) + select(vl_verify_res){ + case (DigestSign_OK){ + return JWS_Sign_OK + } + case (DigestSign_Verification_Failed) { + return JWS_Sign_Verification_Failed + } + case else { + return JWS_Error + } + } + } + case else { + // The selected alg is not implemented + return JWS_Not_Supported + } + } + + + + return JWS_Error +} + + +// Function to unpack and pack the JWS Compact representation (see 3.1 of RFC7515) +// into the JWS_Compact_unpacked by separating each part. + +// returns empty struct if the format of the input is invalid +function f_JWS_Unpack_Compact_Representation(in JWS_Compact_serialized pl_serialized) return JWS_Compact_unpacked { + var TCC_Conversion_ch_list vl_splitted:=f_split(pl_serialized,"."); + if(lengthof(vl_splitted)!=3){ + return {omit,omit,omit} + } + + return {vl_splitted[0],vl_splitted[1],vl_splitted[2]} +} + +function f_JWS_Pack_Compact_Representation(in JWS_Compact_unpacked pl_unpacked) return JWS_Compact_serialized { + var JWS_Compact_serialized ret_val:="" + if(ispresent(pl_unpacked.protected_header)) { + ret_val:=ret_val & pl_unpacked.protected_header + } + ret_val:=ret_val & "." + if(ispresent(pl_unpacked.jws_payload)) { + ret_val:=ret_val & pl_unpacked.jws_payload + } + ret_val:=ret_val & "." + if(ispresent(pl_unpacked.jws_signature)) { + ret_val:=ret_val & pl_unpacked.jws_signature + } + return ret_val +} + +// Converts the JWS object into JWS Compact Serialization format. +// serialize -> Converts the JOSE header and payload to JSON, and use the BASE64URL encoding +// unserialize -> Base64 decode the payload and the JOSE header and extract the values from the JSON + +function f_JWS_Object_serialize(in JWS_Object pl_obj,in JWS_Serialization_Mode pl_ser_mode:=JWS_Basic_Serialization) return JWS_Compact_unpacked { + var JWS_Compact_unpacked vl_ret:={omit,omit,omit} + + var JWS_JSON_Object vl_jose_json:={} + + if(ispresent(pl_obj.jose_header.alg)){ + vl_jose_json[lengthof(vl_jose_json)]:={"alg",{JSON_string:=pl_obj.jose_header.alg}} + } + if(ispresent(pl_obj.jose_header.ppt)){ + vl_jose_json[lengthof(vl_jose_json)]:={"ppt",{JSON_string:=pl_obj.jose_header.ppt}} + } + if(ispresent(pl_obj.jose_header.typ)){ + vl_jose_json[lengthof(vl_jose_json)]:={"typ",{JSON_string:=pl_obj.jose_header.typ}} + } + if(ispresent(pl_obj.jose_header.x5u)){ + vl_jose_json[lengthof(vl_jose_json)]:={"x5u",{JSON_string:=pl_obj.jose_header.x5u}} + } + if(ispresent(pl_obj.jose_header.additional_headers)){ + vl_jose_json := vl_jose_json & pl_obj.jose_header.additional_headers + } + + if(pl_ser_mode == JWS_Deterministic_Serialization){ + vl_jose_json := f_sort_JWS_JSON_Object(vl_jose_json) + } + + vl_ret.protected_header:=enc_Base64(f_enc_JSON({JSON_object:=vl_jose_json}),Base64_Url) + + if(ischosen(pl_obj.jws_payload.json_claim)){ + if(pl_ser_mode == JWS_Deterministic_Serialization){ + vl_ret.jws_payload:=enc_Base64(f_enc_JSON({JSON_object:=f_sort_JWS_JSON_Object(pl_obj.jws_payload.json_claim)}),Base64_Url) + } else { + vl_ret.jws_payload:=enc_Base64(f_enc_JSON({JSON_object:=pl_obj.jws_payload.json_claim}),Base64_Url) + } + } else { + vl_ret.jws_payload:=enc_Base64(pl_obj.jws_payload.generic_payload,Base64_Url) + } + + return vl_ret +} + +function f_JWS_Object_unserialize(in JWS_Compact_unpacked pl_comp, out JWS_Object pl_obj) return integer { // 0 - OK, 1 - Fail + // Initialize the out value + pl_obj.jose_header:={omit,omit,omit,omit,omit} // empty header + pl_obj.jws_payload:={generic_payload:=''O} // empty body + + if(ispresent(pl_comp.protected_header)){ // Decode the header + var octetstring vl_jose_oct:=dec_Base64(pl_comp.protected_header,Base64_Url) + var JSON_generic_val vl_jose_json + var integer vl_dec_res:=f_dec_JSON(vl_jose_oct,vl_jose_json) + if(vl_dec_res == 0 and ischosen(vl_jose_json.JSON_object)){ + // The protected header looks like a JSON object + var integer vl_i:=0 + for(vl_i:=0;vl_i<lengthof(vl_jose_json.JSON_object);vl_i:=vl_i+1){ + select(vl_jose_json.JSON_object[vl_i].key){ + case ("alg"){ + if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ + pl_obj.jose_header.alg:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) + } else { + // The alg should be a string + return 1; + } + } + case ("ppt"){ + if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ + pl_obj.jose_header.ppt:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) + } else { + // The ppt should be a string + return 1; + } + } + case ("typ"){ + if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ + pl_obj.jose_header.typ:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) + } else { + // The typ should be a string + return 1; + } + } + case ("x5u"){ + if(ischosen(vl_jose_json.JSON_object[vl_i].val.JSON_string)){ + pl_obj.jose_header.x5u:=f_unichar2charstr(vl_jose_json.JSON_object[vl_i].val.JSON_string) + } else { + // The x5u should be a string + return 1; + } + } + case else{ + if(not ispresent(pl_obj.jose_header.additional_headers)){ + pl_obj.jose_header.additional_headers:={} + } + pl_obj.jose_header.additional_headers[lengthof(pl_obj.jose_header.additional_headers)]:=vl_jose_json.JSON_object[vl_i] + } + } + } + } else { + // JOSE header is not a JSON object + return 1; + } + } + + if(ispresent(pl_comp.jws_payload)){ + var octetstring vl_payload_oct:=dec_Base64(pl_comp.jws_payload,Base64_Url) + var JSON_generic_val vl_payload_json + var integer vl_dec_res:=f_dec_JSON(vl_payload_oct,vl_payload_json) + if(vl_dec_res == 0 and ischosen(vl_payload_json.JSON_object)){ + // The payload looks like a JSON object + pl_obj.jws_payload.json_claim:=vl_payload_json.JSON_object + } else { + // Generic payload + pl_obj.jws_payload.generic_payload:=vl_payload_oct + } + } + return 0 +} +// Function to encode and decode the JWS JSON serialization format as defined in Chapter 7.2 of RFC7515 + +external function f_enc_JWS_JSON_Serialization(in JWS_JSON_Serialization pdu) return octetstring +with { extension "prototype(convert) encode(JSON)" } + +external function f_dec_JWS_JSON_Serialization(in octetstring stream, out JWS_JSON_Serialization pdu) return integer +with { extension "prototype(backtrack) decode(JSON)" } + + + +// Helper functions, do not use directly +external function f_sort_JWS_JSON_Object(in JWS_JSON_Object pl_unsorted) return JWS_JSON_Object + + +external function decode_JWS_helper_struct(in octetstring os) return JWS_helper_struct +with { extension "prototype(convert) decode(BER:BER_ACCEPT_ALL)" } + +external function encode_JWS_helper_struct(in JWS_helper_struct pdu) return octetstring +with { extension "prototype(convert) encode(BER:BER_ENCODE_DER)" } + + +type JSON_generic_val.JSON_object JWS_JSON_Object + +// The result of the signing or the signiture verification +type enumerated JWS_Sign_Result{ JWS_Sign_OK, // Signed or the signiture is valid + JWS_Sign_Verification_Failed, // Signiture verification failed + JWS_Not_Supported, // The selected alg is not supported + JWS_Error // Something went wrong +} + +type enumerated JWS_Serialization_Mode { JWS_Basic_Serialization, // The JOSE header and the JSON body is encoded as is without any ordering and white space removal + JWS_Deterministic_Serialization // See chapter 9 of RFC 8225 + } + +// The representation of the JOSE header as defined in RFC 7515 +type record JWS_JOSE_Header{ + charstring alg optional, + charstring ppt optional, + charstring typ optional, + charstring x5u optional, + JWS_JSON_Object additional_headers optional // The other headers goes there +} + +// JWS payload representation +type union JWS_Claim_Payload{ + JWS_JSON_Object json_claim, // The payload is a JSON object/claim + octetstring generic_payload // Generic payload. It can be whatever +} + +// The JWS object to be signed +type record JWS_Object{ + JWS_JOSE_Header jose_header, + JWS_Claim_Payload jws_payload +} + +// The unpacked form of the JWS Compact representation (see 3.1 of RFC7515) +type record JWS_Compact_unpacked{ + charstring protected_header optional, // BASE64URL(UTF8(JWS Protected Header)) + charstring jws_payload optional, // BASE64URL(JWS Payload) + charstring jws_signature optional // BASE64URL(JWS Signature) +} + +type charstring JWS_Compact_serialized + + +// Data type for the JWS JSON Serialization Chapter 7.2 of RFC7515 +// Support both the general and flattened syntax +type set JWS_JSON_Serialization{ + charstring jws_payload, + JSON_generic_val unprotected_header optional, + charstring protected_header optional, + charstring jws_signature optional, + JWS_JSON_Signatures_list signatures optional +} with { + variant (jws_payload) "name as 'payload'" + variant (jws_signature) "name as 'signature'" + variant (unprotected_header) "name as 'header'" + variant (protected_header) "name as 'protected'" +} + + +type record of JWS_JSON_Signatures JWS_JSON_Signatures_list + +type set JWS_JSON_Signatures{ + JSON_generic_val unprotected_header optional, + charstring protected_header optional, + charstring jws_signature optional +} with { + variant (jws_signature) "name as 'signature'" + variant (unprotected_header) "name as 'header'" + variant (protected_header) "name as 'protected'" +} + +} with { + encode "JSON" +} diff --git a/src/JWS_func.cc b/src/JWS_func.cc index 7f800f31cef653961f925424194e5b3a71c3b255..66b42dedbeb7f8dd2bf6cfa76e277d898bb941d9 100644 --- a/src/JWS_func.cc +++ b/src/JWS_func.cc @@ -1,48 +1,48 @@ -/****************************************************************************** -* Copyright (c) 2020 Ericsson AB -* All rights reserved. This program and the accompanying materials -* are made available under the terms of the Eclipse Public License v2.0 -* which accompanies this distribution, and is available at -* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html -* -* Contributors: -* Gabor Szalai - initial implementation and initial documentation -******************************************************************************/ -// -// File: JWS_func.cc -// Description: Type definitions for JWS, PASSporT and SHAKEN -/////////////////////////////////////////////// -#include <map> -#include <string> - -#include "JWS_Types.hh" - - - -namespace JWS__Types{ - - -JWS__JSON__Object f__sort__JWS__JSON__Object(const JWS__JSON__Object& pl_unsorted){ - std::map<std::string,int> smap; - for(int i=0; i<pl_unsorted.lengthof();i++){ - TTCN_Buffer buf; - pl_unsorted[i].key().encode_utf8(buf); - smap[std::string((const char *)buf.get_data(),buf.get_len())]=i; - } - - JWS__JSON__Object ret_val=NULL_VALUE; - int a=0; - for( std::map<std::string,int>::iterator it=smap.begin(); it!=smap.end(); it++){ - ret_val[a].key()=pl_unsorted[it->second].key(); - if(pl_unsorted[it->second].val().ischosen(JSON__Generic::JSON__generic__val::ALT_JSON__object)){ - ret_val[a].val().JSON__object()=f__sort__JWS__JSON__Object(pl_unsorted[it->second].val().JSON__object()); - } else { - ret_val[a].val()=pl_unsorted[it->second].val(); - } - a++; - } - return ret_val; -} - -} - +/****************************************************************************** +* Copyright (c) 2020-2023 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +* +* Contributors: +* Gabor Szalai - initial implementation and initial documentation +******************************************************************************/ +// +// File: JWS_func.cc +// Description: Type definitions for JWS, PASSporT and SHAKEN +/////////////////////////////////////////////// +#include <map> +#include <string> + +#include "JWS_Types.hh" + + + +namespace JWS__Types{ + + +JWS__JSON__Object f__sort__JWS__JSON__Object(const JWS__JSON__Object& pl_unsorted){ + std::map<std::string,int> smap; + for(int i=0; i<pl_unsorted.lengthof();i++){ + TTCN_Buffer buf; + pl_unsorted[i].key().encode_utf8(buf); + smap[std::string((const char *)buf.get_data(),buf.get_len())]=i; + } + + JWS__JSON__Object ret_val=NULL_VALUE; + int a=0; + for( std::map<std::string,int>::iterator it=smap.begin(); it!=smap.end(); it++){ + ret_val[a].key()=pl_unsorted[it->second].key(); + if(pl_unsorted[it->second].val().ischosen(JSON__Generic::JSON__generic__val::ALT_JSON__object)){ + ret_val[a].val().JSON__object()=f__sort__JWS__JSON__Object(pl_unsorted[it->second].val().JSON__object()); + } else { + ret_val[a].val()=pl_unsorted[it->second].val(); + } + a++; + } + return ret_val; +} + +} + diff --git a/src/JWS_helper.asn b/src/JWS_helper.asn index 09cb95a1919b2b98bb000fe00f2e23f37dc5aeed..c8226acce943f62ec718e6e115255393a3c8973a 100644 --- a/src/JWS_helper.asn +++ b/src/JWS_helper.asn @@ -1,31 +1,31 @@ --- ***************************************************************************** --- Copyright (c) 2020 Ericsson AB --- All rights reserved. This program and the accompanying materials --- are made available under the terms of the Eclipse Public License v2.0 --- which accompanies this distribution, and is available at --- https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html --- --- Contributors: --- Gabor Szalai - initial implementation and initial documentation --- *****************************************************************************/ --- --- File: JWS_helper.asn --- Description: Type definitions for JWS, PASSporT and SHAKEN --- ///////////////////////////////////////////// -JWS-helper - -DEFINITIONS - - -::= - -BEGIN - -IMPORTS; - -JWS-helper-struct ::= SEQUENCE { - f1 INTEGER, - f2 INTEGER -} - -END \ No newline at end of file +-- ***************************************************************************** +-- Copyright (c) 2020-2023 Ericsson AB +-- All rights reserved. This program and the accompanying materials +-- are made available under the terms of the Eclipse Public License v2.0 +-- which accompanies this distribution, and is available at +-- https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +-- +-- Contributors: +-- Gabor Szalai - initial implementation and initial documentation +-- *****************************************************************************/ +-- +-- File: JWS_helper.asn +-- Description: Type definitions for JWS, PASSporT and SHAKEN +-- ///////////////////////////////////////////// +JWS-helper + +DEFINITIONS + + +::= + +BEGIN + +IMPORTS; + +JWS-helper-struct ::= SEQUENCE { + f1 INTEGER, + f2 INTEGER +} + +END