RFC 2479
Independent Data Unit Protection Generic Security Service Application Program Interface (IDUP-GSS-API)
RFC 2479: Independent Data Unit Protection Generic Security Service Application Program Interface (IDUP-GSS-API) 🎀
okay bestie, the header tea ☕: this is RFC 2479, written by C. Adams from Entrust Technologies in December 1998 🍓. It's Informational, so it's giving "here's useful info for the internet community" vibes 💅, not a binding standard. The header doesn't list any Obsoletes or Updates lines, so it's not replacing or patching any other RFC 🦋.
Status of This Memo ✨
This memo provides information for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited 💌.
Copyright Notice 🌸
Copyright (C) The Internet Society (1998). All Rights Reserved.
Abstract 💜
Okay so the IDUP-GSS-API extends the GSS-API [RFC-2078] for apps that need to protect a generic data unit (like a file or message) in a way that's independent of the protection on any other data unit, and independent of any live contact with the designated "receivers" of that data unit 😭. It's literally made for stuff like secure email, where the data needs protecting with no online connection to the intended recipient(s) at all 📬. The protection on offer includes services like data origin authentication with data integrity, data confidentiality with data integrity, and support for non-repudiation services 🔐. Once it's protected, the data unit can be sent on to the recipient(s), or to an archive, and only gets "unprotected" (processed) days or years later 🕰️. Iconic patience energy.
From here on, that "unit" of data gets called an IDU (Independent Data Unit) 🧚. An IDU can be any size. The app can chop it into pieces and compute the protection one piece at a time, but the resulting protection token still applies to the entire IDU ✂️. The main thing about an IDU is that it's a stand-alone unit of data whose protection is totally independent of any other unit 👑. If an app protects several IDUs and sends them all to one receiver, that receiver can unprotect them in any order and over any time span, and the protection process itself doesn't imply any logical connection between them 🌈. Not me being impressed by how chill that is 🙈.
Like RFC-2078, this IDUP-GSS-API definition gives callers security services in a generic way ✨. It can run on a range of underlying mechanisms and technologies, which means apps can be ported at the source level to different environments 🦋. The spec defines the IDUP-GSS-API services and primitives at a level that doesn't depend on the underlying mechanism or programming language environment. It's meant to be paired with other related specs too 🫶:
- documents defining specific parameter bindings for particular language environments;
- documents defining token formats, protocols, and procedures to be implemented in order to realize IDUP-GSS-API services atop particular security mechanisms.
Table of Contents 📖
1. IDUP-GSS-API Characteristics and Concepts .................. 3
1.1. IDUP-GSS-API Constructs .................................. 5
1.1.1. Credentials ............................................ 5
1.1.2. Tokens ................................................. 5
1.1.3. Security Environment ................................... 6
1.1.4. Mechanism Types ........................................ 6
1.1.5. Naming ................................................. 6
1.1.6. Channel Bindings ....................................... 6
1.2. IDUP-GSS-API Features and Issues ......................... 6
1.2.1. Status Reporting ....................................... 6
1.2.2. Per-IDU Security Service Availability .................. 9
1.2.3. Per-IDU Replay Detection and Sequencing ................ 9
1.2.4. Quality of Protection .................................. 9
1.2.5. The Provision of Time .................................. 12
2. Interface Descriptions ..................................... 13
2.1. Credential management calls .............................. 14
2.1.1. Relationship to GSS-API ................................ 14
2.2. Environment-level calls .................................. 15
2.2.1. Relationship to GSS-API ................................ 15
2.2.2. IDUP_Establish_Env call ................................ 15
2.2.3. IDUP_Abolish_Env call .................................. 19
2.2.4. IDUP_Inquire_Env call .................................. 19
2.3. Per-IDU protection/unprotection calls .................... 20
2.3.1. Relationship to GSS-API ................................ 20
2.3.2. The "SE" Calls ......................................... 21
2.3.3. The "EV" Calls ......................................... 27
2.3.4. The "GP" Calls ......................................... 36
2.4. Special-Purpose calls .................................... 47
2.4.1. Relationship to GSS-API ................................ 47
2.4.2. IDUP_Form_Complete_PIDU ................................ 48
2.5. Support calls ............................................ 49
2.5.1. Relationship to GSS-API ................................ 49
2.5.2. IDUP_Acquire_Cred_With_Auth ............................ 49
2.5.3. IDUP_Get_Token_Details ................................. 50
2.5.4. IDUP_Get_Policy_Info ................................... 53
2.5.5. IDUP_Cancel_Multibuffer_Op ............................. 55
3. Related Activities ......................................... 55
4. Acknowledgments ............................................ 56
5. Security Considerations .................................... 56
6. References ........................................... 56
7. Author's Address ........................................... 56
Appendix A Mechanism-Independent Token Format ................. 57
Appendix B Examples of IDUP Use ............................... 58
Full Copyright Statement ....................................... 70
That's the whole first chunk, bestie! 🌈 Section 1 and the rest of the spec are coming next, and they're where the real protocol magic lives 💖
1. IDUP-GSS-API Characteristics and Concepts ✨
Okay bestie, let's get into the vibe. An IDUP-GSS-API caller is any application that works with IDUs 🎀 and calls on IDUP-GSS-API to protect them with services like data origin authentication with integrity (DOA), confidentiality with integrity (CONF), and/or support for non-repudiation. For that last one, "evidence" means information that, alone or combined with other info, helps establish proof about an event or action. Ngl, the evidence itself doesn't prove something is true or exists, it just helps build the proof 🧐 (see [ISO/IEC] for the full tea on evidence and non-repudiation). The caller hands an IDU to its local IDUP-GSS-API implementation and gets back a token. Then it ships the resulting protected IDU (P-IDU) to a peer or drops it in some storage 📦. When a P-IDU needs to be "unprotected", it goes back into an IDUP-GSS-API implementation for processing. These services can be built on top of secret-key and/or public-key cryptography, so the underlying tech can vary 🦋
During protection, the input IDU buffers might get changed (like the data gets encrypted or encoded somehow) or they might stay exactly the same 💅 Either way, the result is called an "M-IDU" (Modified IDU), so it's distinguishable from the original IDU. Whether the output wraps up the M-IDU depends on what the calling app wants and what the underlying IDUP mechanism can do. So the P-IDU can be either the contents of one output parameter (if it's encapsulated) or the logical concatenation of an unencapsulated token parameter and an M-IDU parameter (if it isn't). In that second case, the protecting app can glue the token and M-IDU together however it likes 🧩 as long as the unprotecting app knows how to split the P-IDU back into its pieces before calling the IDUP unprotection functions. It's giving puzzle energy, honestly.
Any output buffer IDUP hands back (the whole P-IDU or just a chunk of it) is expected to be ready to send right away to the intended receiver(s), if the app wants to. Basically, if an app wants to transmit buffers straight from IDUP, the underlying mechanism shouldn't get in its way 🚀
IDUP-GSS-API separates setting up a security environment (that's the IDUP_Establish_Env() call) from doing the per-IDU protection for IDUs that get protected within that environment afterwards 🌸 The protection and unprotection calls provide DOA, CONF, evidence, and other services, depending on what the calling app asks for and what the mechanism supports.
Here's a little walkthrough of how the sender and receiver of a P-IDU use IDUP-GSS-API. It's mechanism-independent, so it works no matter what's underneath 🧚 This example assumes both sides already finished credential acquisition, and it doesn't cover every option the protection and unprotection calls have, so don't treat it as the whole story, bestie.
The sender starts by calling IDUP_Establish_Env() to set up a security environment. Then, for each IDU that needs protecting, it calls the right protection call (SE, EV, or GP) to do the work. The resulting P-IDU is ready to go to the target. It's either the token by itself, or the token and M-IDU logically concatenated, depending on whether encapsulation was picked or is even available. After that, the sender calls IDUP_Abolish_Env() to flush all the environment-specific info 🧹
The receiver starts by calling IDUP_Establish_Env() so it can unprotect the P-IDU 🫶 Then, for the P-IDU it got, it calls the right unprotection call (SE, EV, or GP). The receiver either already knows which one to use, or it can figure it out with the IDUP_Get_token_details call. Once the unprotection is done, the receiver calls IDUP_Abolish_Env() to clean up the environment-specific stuff too.
Now here's something super important 😭 There is absolutely no synchronization implied or expected between the data buffer size the sender uses as input to the protection calls, the data buffer size the receiver uses as input to the unprotection calls, and the block sizes the underlying protection algorithms (for integrity and confidentiality) need. All of these sizes are meant to be independent 💖 The data buffer sizes used for protection and unprotection are purely a matter of what's going on in the local environment where each call is made. So nobody needs to match sizes, periodt.
IDUP-GSS-API is built around a few basic goals, and they're all very iconic 👑
- Mechanism independence: IDUP-GSS-API gives you an interface to cryptographic security services at a generic level, so it doesn't depend on any particular underlying mechanism. For example, the services can be implemented with secret-key technologies or with public-key approaches 🔐
- Protocol environment independence: IDUP-GSS-API doesn't depend on the communications protocol suites that might be used to transfer P-IDUs, so it can be used across a wide range of protocol environments 🌈
- Protocol association independence: The IDUP-GSS-API security environment construct has nothing whatsoever to do with communications protocol association constructs. That means applications can call IDUP-GSS-API services totally independently of protocol associations 🦋
- Suitability for a range of implementation placements: IDUP-GSS-API clients aren't required to live inside any Trusted Computing Base (TCB) perimeter defined on the system where IDUP-GSS-API is implemented. The security services are specified so they work for both intra-TCB and extra-TCB callers 🍓
1.1. IDUP-GSS-API Constructs
This section breaks down the basic building blocks that make up IDUP-GSS-API 🧱
1.1.1. Credentials
Credentials in IDUP-GSS-API are understood and used just like they're described in GSS-API [RFC-2078] 🪪
1.1.2. Tokens
Tokens in IDUP-GSS-API are also understood and used as described in GSS-API [RFC-2078], with one exception: IDUP-GSS-API doesn't generate any context-level tokens 🙅♀️ Depending on the underlying mechanism, the IDUP-GSS-API token might encapsulate the M-IDU, or it might get logically concatenated with the M-IDU before it's sent to a target. And for some evidence services, the token can be sent on its own, separate from any other data transfer 💌
1.1.3. Security Environment
Okay, this is where people get mixed up, so listen up 👂 The "security environment" in IDUP-GSS-API is totally different from the security contexts used in GSS-API [RFC-2078]. A security environment lives inside the calling application (it's purely local to the caller) and exists so that you can protect or unprotect one or more IDUs using a particular caller credential or set of credentials. In GSS-API, on the other hand, a security context lives between peers (the initiator and the target) and protects the data exchanged between them in real time ⏱️ Even though they're different concepts, the env_handle in IDUP-GSS-API is kinda like the context_handle in GSS-API, because both are a handy way of tying together the whole process of protecting or unprotecting one or more IDUs using a particular underlying mechanism 🎀 And just like GSS-API security contexts, a caller can start and maintain multiple environments, using the same or different credentials 💅
1.1.4. Mechanism Types
Mechanism types in IDUP-GSS-API are understood and used exactly as described in GSS-API [RFC-2078] 🧩
1.1.5. Naming
Naming in IDUP-GSS-API is also understood and used as described in GSS-API [RFC-2078] 📛
1.1.6. Channel Bindings
The concept of channel bindings discussed in GSS-API [RFC-2078] is not relevant to IDUP-GSS-API 🙈 We're skipping that one, bestie.
1.2. IDUP-GSS-API Features and Issues
This section is where we get into the nitty-gritty of IDUP-GSS-API operations and the security services it provides ✨ It also has some commentary on design issues, so grab your snacks 🍓
1.2.1. Status Reporting ✨
okay so status reporting in IDUP-GSS-API works the same way it does in GSS-API [RFC-2078] 💅, plus a bunch of IDUP-specific status codes that are all its own. The major_status codes IDUP uses are listed in Table 1 below. Any code marked with (I) is informatory, which just means it doesn't make the requested operation fail 🌸
minor_status codes give more detailed status info than major_status codes, and they can include codes that belong to the underlying security mechanism. This document doesn't specify them, same as GSS-API 🫶
Table 1: IDUP-GSS-API Major Status Codes 🎀
GSS_S_BAD_MECH: the mech_type asked for isn't supported by the IDUP_GSS-API implementation, so the environment establishment operation fails 😭GSS_S_BAD_QOP: the provided qop_alg value isn't recognized or supported for the environment 🙈GSS_S_BAD_MIC: the received P-IDU has an incorrect integrity field (like a signature or MAC) for the data 💀GSS_S_COMPLETE: the requested operation worked! ✨👑GSS_S_CREDENTIALS_EXPIRED: the credentials tied to this operation have expired, so the operation can't happen 🥀GSS_S_DEFECTIVE_CREDENTIAL: the consistency checks on the credential structure referenced by claimant_cred_handle failed, so no further processing with that credential structure 🚫GSS_S_DEFECTIVE_TOKEN: the consistency checks on the received P-IDU failed, so further processing can't happen 🙅♀️GSS_S_FAILURE: the requested operation couldn't be done for reasons the IDUP-GSS-API level doesn't specify, and there's no interface-defined recovery action available 😭🫠GSS_S_NO_CRED: no environment was established, either because the input cred_handle was invalid or because the caller isn't authorized to access those credentials 🔒IDUP_S_BAD_DOA_KEY: the key used to provide IDU data origin auth. / integ. has expired or been revoked 🗝️IDUP_S_BAD_ENC_IDU: decryption of the received IDU can't finish because the encrypted IDU was invalid or defective (for example, the final block was short or had incorrect padding) 🧩IDUP_S_BAD_KE_KEY: the key used to establish a key for confidentiality between originator and target has expired or been revoked 🔑IDUP_S_BAD_TARG_INFO: the full set of target information is invalid or not enough to protect an IDU, so the P-IDU can't be created 🎯IDUP_S_DEFECTIVE_VERIF: the consistency checks on Service_Verification_Info failed, so processing with that parameter can't continue 🚧IDUP_S_ENCAPSULATION_UNAVAIL(I): the underlying mechanism doesn't support encapsulating the M-IDU into the token 📦IDUP_S_INAPPROPRIATE_CRED: the credentials supplied don't have the info needed for P-IDU unprotection 🪪IDUP_S_INCOMPLETE(I): unprotection of the P-IDU isn't finished yet, so we can't decide whether it's valid. The application should call IDUP_Form_Complete_PIDU and then call this function again with the complete P-IDU ⏳IDUP_S_INCONSISTENT_PARAMS: the supplied parameters clash (for example, only one of two parameters may be supplied, but both were input) ⚡IDUP_S_MORE_OUTBUFFER_NEEDED(I): the output buffer is too small to hold the generated data. The application should keep calling this routine (until GSS_S_COMPLETE is returned) to get all the remaining output data 📤IDUP_S_MORE_PIDU_NEEDED(I): not enough of the P-IDU has been input yet to finish StartUnprotect. The application should call this routine again with another buffer of P-IDU in partial(initial)_pidu_buffer 🧃IDUP_S_NO_ENV: no valid environment was recognized for the env_handle provided 🫥IDUP_S_NO_MATCH: Service_Verification_Info (or evidence_check) and the P-IDU being verified don't match 🙃IDUP_S_REQ_TIME_SERVICE_UNAVAIL: the requested time service (TTIME or UTIME) isn't available in the environment ⏰IDUP_S_SERVICE_UNAVAIL: the underlying mechanism doesn't support the service requested 🚷IDUP_S_SERV_VERIF_INFO_NEEDED(I): the Service_Verification_Info parameter bundle needs to be input before service verification can proceed. The output parameter service_verification_info_id holds an identifier the calling application can use to find the necessary info 🔍IDUP_S_UNKNOWN_OPER_ID: the input prot_oper_id value isn't recognized or supported in the underlying mechanism 🤷♀️
1.2.2. Per-IDU Security Service Availability 🛡️
per-IDU security service availability in IDUP-GSS-API works like it does in GSS-API [RFC-2078], with one twist 🦋 combinations of services that the calling application asks for and the underlying mechanism supports can be applied at the same time to any IDU. This is true for both the SE and the EV calls, but it's true in the fullest sense for the GP calls 💖
GSS-API callers who want per-message security services should check the relevant service OBJECT IDs at environment establishment time. That way they know what the established environment offers is actually suitable for their security needs 🧚
1.2.3. Per-IDU Replay Detection and Sequencing 🔁
the per-IDU replay detection and sequencing concept from GSS-API [RFC-2078] isn't relevant to IDUP-GSS-API. no replay drama here 🙅♀️🌈
1.2.4. Quality of Protection ✨
okay so QOP control in IDUP-GSS-API works basically the way it does in GSS-API [RFC-2078] 💅 but the qop_algs parameter has its own special rules, so let's go through them bestie 🫶
qop_algs for IDUP is a 32-bit unsigned integer with these bit-field assignments:
31 (MSB) (LSB) 0
----------------------------------------------
| U(19) | TS(5) | IA(4) | MA(4) |
----------------------------------------------
where:
Uis a 19-bit Unspecified field (available for future use/expansion), and it MUST be set to zero 🌸TSis a 5-bit Type Specifier (a semantic qualifier whose value specifies the type of algorithm which may be used to protect the corresponding IDU, see below for details) 🦋IAis a 4-bit field enumerating Implementation-specific Algorithms; andMAis a 4-bit field enumerating Mechanism-defined Algorithms.
Now the interpretation, which is giving decision tree energy 🌳 The MA field gets checked first. If it is non-zero, the algorithm used to protect the IDU is the mechanism-specified algorithm matching that integer value.
If MA is zero, then IA gets checked. If that field is non-zero, the algorithm used to protect the IDU is the implementation-specified algorithm matching that integer value. Heads up though, this one can hinder portability 🙈 A particular value might mean one algorithm in one implementation of the mechanism, might not be supported at all, or might mean a completely different algorithm in another implementation.
Finally, if both MA and IA are zero, then TS gets checked. A TS value of zero means the default algorithm for the established mechanism. A non-zero TS value points at a particular algorithm qualifier and picks any algorithm from the mechanism specification that satisfies that qualifier. Which actual algorithm gets picked is an implementation choice, and the calling application does not need to know what was chosen 🧚
These TS values (a.k.a. algorithm qualifiers) are specified, and other values may be added in the future ✨ MAY is doing work here, babe.
When qop_algs is used to select a confidentiality algorithm:
00000 (0) = default confidentiality algorithm
00001 (1) = IDUP_SYM_ALG_STRENGTH_STRONG
00010 (2) = IDUP_SYM_ALG_STRENGTH_MEDIUM
00011 (3) = IDUP_SYM_ALG_STRENGTH_WEAK
11111 (31) = IDUP_NO_CONFIDENTIALITY
When qop_algs is used to select a DOA/integrity algorithm:
00000 (0) = default integrity algorithm
00001 (1) = IDUP_INT_ALG_DIG_SIGNATURE
(integrity provided through a digital signature)
00010 (2) = IDUP_INT_ALG_NON_DIG_SIGNATURE
(integrity without a dig. sig. (e.g., with a MAC))
11111 (31) = IDUP_NO_INTEGRITY
Okay so "strong", "medium", and "weak" are honestly debatable and will probably change over time 😭 But for this version of the spec, here's how they're defined. A confidentiality algorithm is "weak" if its effective key length is 40 bits or less. It's "medium-strength" if the effective key length is strictly between 40 and 80 bits. And it's "strong" if the effective key length is 80 bits or greater. (Effective key length just means how much computational effort it takes to break a cipher using the best-known cryptanalytic attack against that cipher 🔥)
A five-bit TS field can hold up to 30 qualifiers for each of confidentiality and integrity, since "0" is reserved for "default" and "31" is reserved for "none," as shown above. This document specifies three for confidentiality and two for integrity, which leaves a lot of room for the future 🌈 People have suggested qualifiers like "fast", "medium-speed", and "slow," but those are hard to quantify (and they depend on platform and processor anyway), so they got left out of this first spec. The goal is for TS terms to be quantitative, environment-independent qualifiers of algorithms, as much as that's possible 💜
Here's what using qop_algs is ultimately meant to look like:
- TS values are specified at the IDUP-GSS-API level and are therefore portable across mechanisms. Applications that know nothing about algorithms can still choose the "quality" of protection for their message tokens 💖
- MA values are specified at the mechanism level and are therefore portable across implementations of a mechanism 🎀
- IA values are specified at the implementation level (in user documentation, for example) and are therefore typically non-portable. An application that is aware of its own mechanism implementation and the mechanism implementation of its intended P-IDU recipient, however, is free to use these values, since they will be perfectly valid and meaningful for protecting IDUs between those entities 🫶
The receiver of a P-IDU MUST pass back to its calling application (in IDUP_Start_Unprotect()) a qop_algs parameter with all relevant fields set. For example, if triple-DES has been specified by a mechanism as algorithm 8, then a receiver of a triple-DES-protected P-IDU MUST pass to its application (TS=1, IA=0, MA=8). That way, the application is free to read whatever part of the qop_algs parameter it understands (TS or IA/MA) 👑
1.2.5. The Provision of Time ⏰
IDUP mechanisms SHOULD make provision in their protocols for carrying time information from originator to target(s). In other words, a target (a legitimate recipient) should get some indication during unprotection of the time at which the protection operation took place. This is especially important if the mechanism offers non-repudiation services, because in some cases evidence verification can only be achieved if you know when the evidence was generated 🧐
Depending on the platform and resources available to the implementation, an IDUP environment may have access to a source of trusted (secure) time, untrusted (local) time, both kinds of time, or no time at all. OBJECT IDs indicating that availability get returned by the IDUP_Establish_Env() call. When starting a protection operation, an application MAY specify which time services it wants applied to the IDU. Similarly, for unprotection, an application MAY specify which kind of time (if any) to consult when establishing the validity of the P-IDU. Specifying both kinds of time means the calling application does not care which kind gets used 🌸
The IDUP calls that take a time parameter specify that parameter's type as INTEGER. In all cases, this INTEGER is defined as the number of seconds that have elapsed since midnight, January 1, 1970, coordinated universal time ⭐
2. Interface Descriptions ✨
This section describes the IDUP-GSS-API's operational interface, which splits the set of calls into five groups. Credential management calls deal with acquiring and releasing credentials for API callers. Environment-level calls handle managing the security environment for an API caller. Per-IDU calls handle protecting or unprotecting individual IDUs in established security environments. Special-purpose calls cover unusual or auxiliary evidence generation/verification requirements. Support calls provide extra functions that are useful to IDUP-GSS-API callers. Table 2 groups and summarizes the calls in table form 🦋
Table 2: IDUP-GSS-API Calls
CREDENTIAL MANAGEMENT
(see the calls given in Section 2.1 of GSS-API [RFC-2078])
ENVIRONMENT-LEVEL CALLS
IDUP_Establish_Env
IDUP_Abolish_Env
IDUP_Inquire_Env
PER-IDU CALLS
SE (SIGN,ENCRYPT) CALLS
IDUP_SE_SingleBuffer_Protect
IDUP_SE_SingleBuffer_Unprotect
IDUP_SE_MultiBuffer_StartProtect
IDUP_SE_MultiBuffer_EndProtect
IDUP_SE_MultiBuffer_StartUnprotect
IDUP_SE_MultiBuffer_EndUnprotect
IDUP_SE_Process_Buffer
EV (EVIDENCE) CALLS
IDUP_EV_SingleBuffer_Generate
IDUP_EV_SingleBuffer_Verify
IDUP_EV_MultiBuffer_StartGenerate
IDUP_EV_MultiBuffer_EndGenerate
IDUP_EV_MultiBuffer_StartVerify
IDUP_EV_MultiBuffer_EndVerify
IDUP_EV_Process_Buffer
GP (GENERAL PROTECTION) CALLS
IDUP_Start_Protect
IDUP_Protect
IDUP_End_Protect
IDUP_Start_Unprotect
IDUP_Unprotect
IDUP_End_Unprotect
SPECIAL-PURPOSE CALLS (might not be supported by all mechanisms)
IDUP_Form_Complete_PIDU
SUPPORT CALLS
IDUP_Acquire_cred_with_auth
IDUP_Get_Token_Details
IDUP_Get_Policy_Info
IDUP_Cancel_Multibuffer_Op
(see also the calls given in Section 2.4 of GSS-API [RFC-2078])
For conformance to this specification, IDUP-GSS-API implementations MUST support the credential management calls, the environment-level calls, some subset of the per-IDU calls, and the support calls (except where explicitly stated otherwise in Section 2.5). Which per-IDU calls are supported depends on the underlying mechanisms supported, and it will typically be the SE calls, the EV calls, or both. As stated in Section 2.3.2.1, implementations are encouraged to support the more powerful GP calls to anticipate the future needs of application developers, but this is not required for conformance 💅
2.1. Credential management calls 🔐
2.1.1. Relationship to GSS-API
Credential management in IDUP-GSS-API is understood and used as described in GSS-API [RFC-2078]. The calls given in Section 2.1 of GSS-API (including all associated parameters) are unchanged. The one twist is how the cred_usage parameter in those GSS-API calls gets interpreted for IDUP purposes:
ENCRYPT_ONLY 8
DECRYPT_ONLY 16
SIGN_ONLY 32
VERIFY_ONLY 64
The values above MAY be logically OR'ed together in any desired combination to restrict credential usage (and OR'ing all of the values results in NO_RESTRICTION). Future possible values for this parameter are for further study 🌟
The call IDUP_Acquire_cred_with_auth has been added as a support call in this specification to permit authenticated credential acquirement. See Section 2.5.2 for details 🎀
2.2. Environment-level calls 🌍
This group of calls is all about establishing and managing an environment for IDU protection and unprotection. Before protecting or unprotecting any IDU, an application MUST call IDUP_Establish_Env() to initialize environment information and select the underlying IDUP-GSS mechanism to be used. A series of protection or unprotection calls then processes each IDU, and the protection calls produce a P-IDU for each one. Finally, IDUP_Abolish_Env() gets called to flush all environment information 🧹
Semantically, acquiring credentials and establishing an environment is (in many cases) analogous to logging in to a system. It authenticates a local user to the system and gives that user access to a set of operations they can perform 🔑
2.2.1. Relationship to GSS-API
The set of calls described in this section is used in place of the calls described in Section 2.2 of GSS-API [RFC-2078], since those calls are specific to a session-oriented environment 🦋
2.2.2. IDUP_Establish_Env call 🦋
okay bestie, this is the call that sets up the whole environment 💅 it reads your credentials, builds everything needed to protect or unprotect IDUs, and gives you back a handle to use later ✨
Inputs: o claimant_cred_handle CREDENTIAL HANDLE,
-- NULL parameter specifies "use default"
o req_mech_type OBJECT IDENTIFIER,
-- NULL parameter specifies "use default"
o req_environmentPolicies EnvironmentPolicies,
-- NULL parameter specifies "use default"
o req_services SET OF OBJECT IDENTIFIER,
-- GSS_C_NO_OID_SET requests full set of services available
-- for req_mech_type
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o env_handle ENVIRONMENT HANDLE,
o actual_mech_type OBJECT IDENTIFIER,
-- actual mechanism always indicated, never NULL
o actual_environmentPolicies EnvironmentPolicies,
-- actual values always indicated, never NULL
o ret_services SET OF OBJECT IDENTIFIER,
Return major_status codes:
o GSS_S_COMPLETE
-- environment-level information was successfully initialized,
-- and IDU / P-IDU processing can begin.
o GSS_S_DEFECTIVE_CREDENTIAL
o GSS_S_NO_CRED
o GSS_S_CREDENTIALS_EXPIRED
-- the credentials provided through claimant_cred_handle are
-- no longer valid, so environment cannot be established.
o GSS_S_BAD_MECH
o GSS_S_FAILURE
The status codes are the good stuff, so here's the vibe: GSS_S_COMPLETE means your environment is set up and you're ready to rock IDU and P-IDU processing 🔥 If your credentials are defective, missing, or expired, you get one of the credential codes instead, and no environment gets built 💀 GSS_S_BAD_MECH and GSS_S_FAILURE cover the rest of the drama 🙈
Here are the structures for passing policy in and out:
EnvironmentPolicies ::= SEQUENCE {
confPolicy [0] PolicyAndTime OPTIONAL,
-- NULL parameter (on input) specifies "use default"
integPolicy [1] PolicyAndTime OPTIONAL,
-- NULL parameter (on input) specifies "use default"
evidencePolicy [2] PolicyAndTime OPTIONAL }
-- NULL parameter (on input) specifies "use default"
PolicyAndTime ::= SEQUENCE {
policy OBJECT IDENTIFIER,
-- this environment-level policy identifier is separate from
-- the policy provisions connected with credentials, if they exist
time INTEGER
-- on input: the policy rules available at the specified time
-- on output: the time at which the policy rules came into effect
-- (defined to be the number of seconds elapsed since midnight,
-- January 1, 1970, coordinated universal time)
endTime INTEGER OPTIONAL }
-- on input: unused
-- on output: the expiration time of the given policy rules
This call is for an application that protects or unprotects IDUs. Using the info in the credentials structure referenced by claimant_cred_handle, IDUP_Establish_Env() sets up the data structures it needs for that work. The claimant_cred_handle, if non-NULL, must correspond to a valid credentials structure.
It hands back an env_handle, and that's the key for every future call in this environment 🔑 Protection, unprotection, and IDUP_Abolish_Env() calls all take this handle as their env_handle input. Getting the P-IDU to its recipients is on you: you have to set up a communications path to the intended recipients and send the P-IDU over it. That can happen after IDUP_Abolish_Env() is called, so keep that in mind 🫶
The req_services parameter is how you ask for stuff. You can request data origin authentication with integrity, confidentiality with integrity, evidence generation, and/or evidence verification, plus "trusted" or "untrusted" time services ⏰ Asking for evidence generation or verification means the calling application may wish to generate or verify evidence for non-repudiation purposes 🧾
Heads up, this part is a plot twist 😭 An IDU protector can ask for a flag to go into the P-IDU, telling the recipient to send back evidence of the type "non-repudiation of delivery". BUT the IDUP-GSS-API cannot guarantee that evidence will ever be sent by itself, because there's no way to force a target to send an evidence_token back to the IDU protector. Not me being dramatic, it's literally how it works.
Not every mech_type has every feature, so ret_services tells you what you actually got. It depends on what the mechanism can do and the OIDs the initiator asked for 💅 That value is only defined when major_status says COMPLETE. Missing part of your wishlist doesn't make establishment fail. If the service set isn't good enough for you, it's your call to abolish the environment 🙅♀️ And the returned mech_type always tells you the specific mechanism in use, never "default" ✨
Now the OIDs for protection and unprotection services. The OID iso.org.dod.internet.security.services, 1.3.6.1.5.7, was assigned by IANA, and some of the services under that node look like this. Expect this list to grow over time 🌈
PER_CONF = { 1.3.6.1.5.7.1.1 }
-- perform data confidentiality (i.e., encrypt data)
PER_CONF_FULL = { 1.3.6.1.5.7.1.3 }
-- perform full confidentiality (i.e., encrypt data and sig)
-- (may be used only when PER_DOA is requested simultaneously)
PER_DOA = { 1.3.6.1.5.7.3.1 }
-- perform data origin authentication with data integrity
PER_DOA_CIPH = { 1.3.6.1.5.7.3.3 }
-- perform DOA with DI over ciphertext (rather than plaintext)
-- (may be used only when PER_CONF is requested simultaneously)
PER_POO = { 1.3.6.1.5.7.4.1 }
-- perform (i.e., create) non-repudiable "proof of origin"
PER_POD = { 1.3.6.1.5.7.4.3 }
-- perform (i.e., create) non-repudiable "proof of delivery"
REC_CONF = { 1.3.6.1.5.7.1.2 }
-- receive data confidentiality (i.e., decrypt data)
REC_CONF_FULL = { 1.3.6.1.5.7.1.4 }
-- receive full confidentiality (i.e., decrypt data and sig)
-- (may be used only when REC_DOA is received simultaneously)
REC_DOA = { 1.3.6.1.5.7.3.2 }
-- receive / verify DOA with data integrity
REC_DOA_CIPH = { 1.3.6.1.5.7.3.4 }
-- verify DOA with DI over ciphertext (rather than plaintext)
-- (may be used only when PER_CONF is received simultaneously)
REC_POO = { 1.3.6.1.5.7.4.2 }
-- receive / verify "proof of origin"
REC_POD = { 1.3.6.1.5.7.4.4 }
-- receive / verify "proof of delivery"
TTIME = { 1.3.6.1.5.7.7.1 }
-- trusted time availability
UTIME = { 1.3.6.1.5.7.7.2 }
-- untrusted time availability
Checking what's supported is easy once you know the return values 👀 PER_CONF in ret_services says whether confidentiality is supported, so you know if an encryption request can be honored. PER_DOA works the same way for DOA services, and PER_POO and PER_POD tell you whether evidence generation is available. TTIME and UTIME show whether trusted and untrusted time are available for protection and unprotection ⏰
One thing that's different from a GSS "context": an IDUP environment doesn't have its own explicit lifetime 🙃 It relies on the lifetime of the calling entity's credential, the one you set in the GSS_Acquire_cred() call. Once that credential expires (or gets deleted some other way), no new operations are allowed in the IDUP environment. Operations that already started, like the Protection set of calls, can still be finished 🏁
2.2.3. IDUP_Abolish_Env call 🧹
This one is the cleanup crew. It flushes the environment-specific info. Once an environment is set up, the cached credential and environment info sticks around until you call IDUP_Abolish_Env() or the credential lifetime runs out.
Input:
o env_handle ENVIRONMENT HANDLE
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
Return major_status codes:
o GSS_S_COMPLETE
-- the relevant environment-specific information was flushed.
o IDUP_S_NO_ENV
o GSS_S_FAILURE
Once an environment is deleted, trying to do IDU processing on it gets you error returns, so don't try it 🙅♀️
2.2.4. IDUP_Inquire_Env call 🔍
This is your "wait, what did I even get?" call. You hand it an env_handle, and it tells you the details of the environment.
Input:
o env_handle ENVIRONMENT HANDLE,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o mech_type OBJECT IDENTIFIER,
-- the mechanism supporting this environment
o environmentPolicies EnvironmentPolicies,
-- the environment policies in effect
o ret_services SET OF OBJECT IDENTIFIER,
Return major_status codes:
o GSS_S_COMPLETE
-- referenced environment is valid and mech_type and other return
-- values describe the characteristics of the environment.
o GSS_S_CREDENTIALS_EXPIRED
o IDUP_S_NO_ENV
o GSS_S_FAILURE
If the environment is valid, GSS_S_COMPLETE comes back along with the mech_type and the other return values that describe it 💖 Otherwise you might see GSS_S_CREDENTIALS_EXPIRED, IDUP_S_NO_ENV, or GSS_S_FAILURE. This routine is all about giving environment-related info back to the caller 🌸
2.3. Per-IDU calls 🎀
Okay, now we're getting to the main event. This group of calls does IDU protection and unprotection on an environment that's already set up. Some of them might block while waiting on network interactions, depending on the underlying mechanism. An IDU's protector or the P-IDU's recipient can call them. They come in pairs: the output of the protection calls is usually what you feed into the unprotection calls 👯♀️
These calls can handle the caller-requested stuff: data origin authentication with data integrity, confidentiality with data integrity, evidence, and evidence-requested-from-target services 🧁
The protection side outputs a token that holds everything needed to unprotect the IDU. That token gets passed to the target (maybe separately from the M-IDU), and the unprotection calls on that system process it. Depending on what's needed, unprotection does decipherment, DOA verification, evidence verification, or notification of evidence requested 🔐
Each of the two main operations, protection and unprotection, can be split into three parts: "Start_Operation", "Operation", and "End_Operation". The "Operation" part can be called once for each buffer of input data, which is super handy when you're processing one buffer at a time 🧩 "Start_Operation" lets you set or retrieve the right "Quality" for the processing. "Operation" does the actual work: it takes a buffer of input and may hand back a buffer of output. "End_Operation" handles the cleanup and either creates the right token or tells you whether the input token checked out ✅
If the whole IDU or P-IDU fits in one buffer, you don't need the three-part version at all. A single call does protection or unprotection, which keeps your app code simple 💅
2.3.1. Relationship to GSS-API 🧠
The calls in this section take the place of GSS_GetMIC(), GSS_VerifyMIC, GSS_Wrap(), and GSS_Unwrap(), which are specified in [RFC-2078]. Those calls are made for a session-oriented environment, which is why IDUP needs its own set 💜
2.3.2. The "SE" Calls 🌟
2.3.2.1. IDUP_SE Purpose
okay so the "SE" group of calls is the simple, high-level interface for when app devs only need signature and encryption protect/unprotect services 💅✨ it covers both the single-buffer and multiple-buffer IDU cases, and you can use it for signing only, encrypting only, signing and encrypting (either order, with or without the signature being visible in the result), and "clear signing" 🖊️ (where the data isn't modified at all and the signature comes back as its own separate item). [Note that encapsulation occurs in all cases except for clear signing, so these calls give you functionality similar to the GSS_Wrap call. 🎀]
quick note: "signing" is used in its most generic sense 🧚 so it doesn't necessarily mean public-key techniques. other standards efforts have called this "sealing," so if you see that word, it's the same vibe 🫶
the SE calls can be seen by mechanism implementors as an "API" on top of the more powerful GP calls we'll get to later 💜 so they can be simple mapping functions to those calls (when those optional calls are supported). app callers might find the SE calls are all they need for a lot of environments 🌸 later on, if they need non-repudiation or "directed receipts" kinds of services, they can look at the EV calls (or the GP calls, when those are supported, if they want complicated and sophisticated combos of services) 🔥 to make that glow-up path smoother, mechanism implementors are encouraged to support the full set of IDUP calls (i.e., the SE, EV, and GP calls) even though some apps will only use the SE calls in the short term 👑
2.3.2.2. IDUP_SE Parameter Bundles
the "parameter bundles" idea shows up in the calls in the next subsections 🎀 it keeps things tidy and makes the purpose and use clearer. see Section 2.3.4.1 for the full tea on parameter bundles 🫖
these parameter bundles are used in the "SE" protection and unprotection sets of calls:
o Protect_Options PARAMETER BUNDLE
o protect_operation INTEGER {
sign_only (0),
encrypt_only (1),
sign_and_encrypt (2),
-- let mechanism choose order (and readability of signature)
sign_then_encrypt_data (3),
-- sign, then encrypt plaintext (leaving signature in clear)
sign_then_encrypt_full (4),
-- sign, then encrypt everything (including signature)
encrypt_then_sign (5),
-- encrypt, then sign the ciphertext
clear_sign_only (6)
} OPTIONAL,
o protect_oper_oid OBJECT IDENTIFIER OPTIONAL,
-- may be used in place of above parameter if OID is known
o sign_qop_alg UNSIGNED INTEGER,
o sign_qop_algID AlgorithmIdentifier, --overrides sign_qop_alg
o enc_qop_alg UNSIGNED INTEGER,
o enc_qop_algID AlgorithmIdentifier, --overrides enc_qop_alg
o idu_type_string OCTET STRING,
-- type of the IDU ("data", "e-mail doc", MIME type, etc.)
o pidu_type_string OCTET STRING,
o mech_indep_encap_req BOOLEAN -- (see Appendix A)
o PIDU_Information PARAMETER BUNDLE
o protect_options Protect_Options,
o originator_name INTERNAL NAME,
o originator_role Originator_Role, -- (see Section 2.3.4.1)
o protection_time INTEGER,
o Bad_Target_Name PARAMETER BUNDLE, -- same as in Section 2.3.3.2
o bad_targ_name INTERNAL NAME,
o bad_targ_status INTEGER,
-- a status flag giving the reason for rejection of the name
-- in bad_targ_name. Specified reasons include:
-- SYNTAX_INVALID (0) the syntax of the name is invalid;
-- NAME_UNRECOGNIZED (1) the name is not recognized;
-- NAME_AMBIGUOUS (2) the name cannot be resolved;
-- ACCESS_DENIED (3) access to this target is denied;
-- CERTIFICATE_NOT_FOUND (4) the encryption certificate of the
target could not be found.
o Target_Info PARAMETER BUNDLE, -- same as in Section 2.3.3.2
o targ_names SET OF INTERNAL NAME,
o bad_targ_count INTEGER,
o bad_target_names SET OF Bad_Target_Name,
2.3.2.3. IDUP_SE major_status codes
these are the major_status return codes defined for the "SE" calls in this section 📋
o GSS_S_COMPLETE
o IDUP_S_MORE_OUTBUFFER_NEEDED
-- returned (by any SE call) to indicate that there is more output
-- data than can fit into the supplied buffers. The application
-- should save the returned data and call again to retrieve the
-- remaining output.
o IDUP_S_MORE_PIDU_NEEDED
-- indicates that more PIDU data is needed for the StartUnprotect
-- operation (e.g., so that PIDU_Information or initial_idu_buffer
-- may be returned).
o IDUP_S_INCONSISTENT_PARAMS
o GSS_S_CREDENTIALS_EXPIRED
o IDUP_S_NO_ENV
o GSS_S_BAD_QOP
o GSS_S_FAILURE
if Target_Info is used as an input parameter (like when an encryption operation is happening), there's one more major_status return code you should know about 👀
o IDUP_S_BAD_TARG_INFO
note for this one: if one or more of the targets in targ_names can't be used as a valid recipient of the P-IDU, those names come back in bad_targ_names (with their status codes in bad_targ_status). 🥺 as long as at least one target is usable, the call does NOT fail (so IDUP_S_BAD_TARG_INFO isn't returned). it's up to the caller to decide whether to stop IDU protection if the usable target set isn't good enough for what they need 💅
2.3.2.4. IDUP_SE_SingleBuffer_Protect call
inputs:
o env_handle ENVIRONMENT HANDLE,
o Protect_Options PARAMETER BUNDLE,
o Target_Info PARAMETER BUNDLE,
o idu_buffer OCTET STRING
o additional_protection BOOLEAN
-- TRUE if idu_buffer is the output of a previous protection
-- operation (i.e., if this is the second (or higher) in a
-- series of SE/EV protection calls)
outputs:
o major_status INTEGER,
o minor_status INTEGER,
o pidu_buffer OCTET STRING,
o sig_token OCTET STRING
-- used if Protect_Options is clear_sign_only
using the security environment referenced by env_handle, encrypt and/or sign the supplied IDU ✨ if "clear signing" is performed, the signature comes back in sig_token and pidu_buffer may be empty (depends on the underlying mechanism) 🦋
2.3.2.5. IDUP_SE_SingleBuffer_Unprotect call
inputs:
o env_handle ENVIRONMENT HANDLE,
o pidu_buffer OCTET STRING,
-- may contain an IDU if sig_token is non-NULL (i.e., if
-- clear_sign_only protection was applied)
o sig_token OCTET STRING
outputs:
o major_status INTEGER,
o minor_status INTEGER,
o idu_buffer OCTET STRING,
-- may be empty if clear_sign_only protection was applied (depends
-- on underlying mechanism)
o PIDU_Information PARAMETER BUNDLE
o additional_unprotection BOOLEAN
-- TRUE if idu_buffer should be input to another unprotection
-- operation (i.e., if this should not be the last in a series
-- of SE/EV unprotection calls)
using the security environment referenced by env_handle, decrypt and/or verify the supplied PIDU and get back the contained IDU along with all the available PIDU_Information 🌈
2.3.2.6. IDUP_SE_MultiBuffer_StartProtect call
inputs:
o env_handle ENVIRONMENT HANDLE,
o Protect_Options PARAMETER BUNDLE,
o Target_Info PARAMETER BUNDLE,
o additional_protection BOOLEAN, -- (see Section 2.3.2.4)
o idu_size INTEGER -- (see Section 2.3.4.2)
outputs:
o major_status INTEGER,
o minor_status INTEGER,
o initial_pidu_buffer OCTET STRING
-- may be empty (depends on underlying mechanism)
using the security environment referenced by env_handle, set up the data structures needed to start signing and/or encrypting the IDU 🔥 (the IDU gets supplied in multiple buffers to the Process_Buffer call).
2.3.2.7. IDUP_SE_MultiBuffer_EndProtect call
inputs:
o env_handle ENVIRONMENT HANDLE
outputs:
o major_status INTEGER,
o minor_status INTEGER,
o final_pidu_buffer OCTET STRING,
o sig_token OCTET STRING
-- used if Protect_Options was clear_sign_only
using the security environment referenced by env_handle, finish the protection processing on the data and put the computed output in final_pidu_buffer and/or sig_token. 🥹 a successful IDUP_SE_MultiBuffer_EndProtect() does NOT guarantee that unprotection can definitely work when the P-IDU arrives at the target (for example, it could get damaged in transit).
ngl this is the part where you remember that networks are chaos 💀 protection succeeding at the sender doesn't mean the receiver is guaranteed a clean unprotect 🫠
2.3.2.8. IDUP_SE_MultiBuffer_StartUnprotect call
inputs:
o env_handle ENVIRONMENT HANDLE,
o initial_pidu_buffer OCTET STRING,
o sign_qop_alg_in UNSIGNED INTEGER,
-- used if Protect_Options was clear_sign_only (and calling
-- application has prior knowledge of signing alg. applied);
-- if NULL, then sig_token must be supplied
o sig_token OCTET STRING
-- used if Protect_Options was clear_sign_only;
-- if NULL, then sign_qop_alg_in must be supplied
outputs:
o major_status INTEGER,
o minor_status INTEGER,
o PIDU_Information PARAMETER BUNDLE,
-- returns all available information
o initial_idu_buffer OCTET STRING
-- may be empty
using the security environment referenced by env_handle, set up the data structures needed to start decrypting and/or verifying the PIDU 🧩 (the PIDU gets supplied in multiple buffers to the Process_Buffer call).
the parameters sign_qop_alg_in and sig_token should not both be supplied (i.e., they should not both be non-NULL). 🙅♀️ but if they both are non-NULL, sig_token is treated as the authoritative one, since it's the token made at protection time, so it's guaranteed to carry the info needed to unprotect 🔐
2.3.2.9. IDUP_SE_MultiBuffer_EndUnprotect call
inputs:
o env_handle ENVIRONMENT HANDLE,
o sig_token OCTET STRING OPTIONAL
-- used if Protect_Options was clear_sign_only and sig_token was
-- not available when StartUnprotect was called
outputs:
o major_status INTEGER,
o minor_status INTEGER,
o PIDU_Information PARAMETER BUNDLE,
-- returns all available information
o final_idu_buffer OCTET STRING -- may be empty
o additional_unprotection BOOLEAN -- (see Section 2.3.2.5)
using the security environment referenced by env_handle, finish the decryption and/or verification processing on the data and put any leftover output in final_idu_buffer 🎀
2.3.2.10. IDUP_SE_Process_Buffer call 💖
okay so this is the workhorse call 🧚 the app keeps feeding it fresh chunks of data, over and over, until every buffer of the IDU/PIDU has been processed. Then it calls the matching End() call to wrap things up 🎀
Inputs:
o env_handle ENVIRONMENT HANDLE,
o input_buffer OCTET STRING,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o output_buffer OCTET STRING
-- may be zero length (depends on underlying mechanism and
-- corresponding Start() call and Protect_Options value)
Using the security environment referenced by env_handle, it keeps processing the data in input_buffer. If there's output ready, it lands in output_buffer ✨
2.3.3. The "EV" Calls 🦋
2.3.3.1. IDUP_EV Purpose 🎀
the "EV" group is the simple, high-level interface for devs who only care about evidence and don't need to touch encryption or integrity stuff 💅 it covers both the single-buffer and multiple-buffer IDU cases, and it can generate and verify evidence tokens for several different evidence types.
here's the evidence list. ngl it's not exhaustive, and it may get extended in future versions of this spec 👑
- "Non-repudiation of Origin" stops a message creator from falsely denying that they created and sent a message 🙅♀️
- "Non-repudiation of Creation" stops a message creator from falsely denying that they created a message ✍️
- "Non-repudiation of Sender" stops a message creator from falsely denying that they sent a message (even if the sender didn't necessarily create it) 📮
- "Non-repudiation of Delivery" stops a message recipient from falsely denying that they received and looked at the content 👀
- "Non-repudiation of Receipt" stops a message recipient from falsely denying that they received a message (even if they never actually looked at the content) 📬
- "Non-repudiation of Approval" stops a message recipient from falsely denying that they approved the content of a received message 💜
evidence shows up as an evidence token, and there are two forms ✨
- tokens that include the associated data
- tokens without included data, but with a unique reference to the associated data
evidence tokens can be freely distributed 🦋 anyone holding an evidence token (and the associated data, if it isn't included in the token) can verify the evidence, as long as they have the right credentials, which include the definition of security policies. keys alone aren't enough to verify evidence tokens, so no shortcuts 🙈 and any holder can store a token (plus the associated data, if it isn't in the token) and verify it later 🫶
the calls that are specific to evidence are:
- Generate_token, which makes a non-repudiation token using the current environment. The token it generates can be any of these:
- 1 - an evidence token
- 2 - a token containing a request for an evidence, which says which evidence type should be generated by the recipient(s) and sent back to some entities (who may or may not include the sender)
- 3 - a token containing an evidence token that answers an evidence request made earlier
- 4 - a token that includes both an evidence and a request for another evidence to be provided
- Verify_evidence, which verifies the evidence token using the current environment. It returns a major_status code that tells you whether the evidence in a token is complete, meaning it can be successfully verified (maybe years later) 🔥 if the evidence isn't complete, the token can be passed to form_complete_pidu to fix that
more helpful calls for evidence services:
IDUP_Get_token_details(see Section 2.5.3)IDUP_Form_Complete_PIDU(see Section 2.4.2)
2.3.3.2. IDUP_EV Parameters 🌸
these parameter bundles are used in the "EV" protection and unprotection sets of calls 🍓
o Nr_Options PARAMETER BUNDLE
o evidence_type INTEGER {
no_evidence (0)
-- used when request-only token desired
proof_of_receipt (1),
proof_of_delivery (2),
proof_of_approval (3),
proof_of_creation (4),
proof_of_sender (5),
proof_of_origin (6)
} OPTIONAL,
o evidence_type_oid OBJECT IDENTIFIER OPTIONAL,
-- may be used in place of above parameter if OID is known
o evidence_validity_duration INTEGER,
-- duration_in_minutes
-- DURATION_HOUR = 60;
-- DURATION_DAY = 1440;
-- DURATION_WEEK = 10080;
-- DURATION_MONTH = 43200;// 30 days
-- DURATION_YEAR = 525600;//365 days
o mech_indep_encap_req BOOLEAN -- (see Appendix A)
o Originator_Information PARAMETER BUNDLE
o token_generator_name INTERNAL NAME,
-- obtained from the credentials of the originator
-- (e.g., from its public key certificate)
o token_generator_role Originator_Role OPTIONAL,
-- (see Section 2.3.4.1)
o protection_time INTEGER OPTIONAL
o Bad_Target_Name PARAMETER BUNDLE -- (see Section 2.3.2.2)
o bad_targ_name INTERNAL NAME,
o bad_targ_status INTEGER
-- a status flag giving the reason for rejection of the
-- name in bad_targ_name
o Target_Info PARAMETER BUNDLE -- same as in Section 2.3.2.2
o targ_names SET OF INTERNAL NAME,
o bad_targ_count INTEGER,
o bad_target_names SET OF Bad_Target_Name
o Request_Features PARAMETER BUNDLE
o requested_evidence_type INTEGER {
no_evidence (0), - used when no token desired
proof_of_receipt (1),
proof_of_delivery (2),
proof_of_approval (3), },
o nr_req_policy OBJECT IDENTIFIER,
o evidence_from Target_Info,
o evidence_to Target_Info,
o include_received_token_in_evidence BOOLEAN
the data_type used in the "EV" protection calls is:
o Nr_Operation INTEGER {
evidence_and_or_evidence_request (1),
returned_evidence (2) }
2.3.3.3. IDUP_EV major_status codes 🔥
these are the major_status return codes defined for the "EV" calls in this section:
o GSS_S_COMPLETE
-- indicates that the evidence is complete
o IDUP_S_INCOMPLETE
o IDUP_S_MORE_OUTBUFFER_NEEDED
-- returned (by any EV call) to indicate that there is more output
-- data than can fit into the supplied buffers. The application
-- should save the returned data and call again to retrieve the
-- remaining output.
o IDUP_S_INCONSISTENT_PARAMS
o GSS_S_CREDENTIALS_EXPIRED
o IDUP_S_NO_MATCH
o IDUP_S_NO_ENV
o GSS_S_FAILURE
if Target_Info is used as an input parameter (aka an evidence is being requested), there's one more code you can get back:
o IDUP_S_BAD_TARG_INFO
heads up on this one 🙈 if one or more of the targets intarg_namescan't be used as a valid recipient of the P-IDU, those names come back inbad_targ_names(with their status codes inbad_targ_status). But as long as at least one target is usable, the call does NOT fail, soIDUP_S_BAD_TARG_INFOisn't returned. It's the caller's choice whether to stop IDU protection when the usable targets aren't good enough for what they need 💅
2.3.3.4. IDUP_EV_SingleBuffer_Generate call ✨
Inputs:
o env_handle ENVIRONMENT HANDLE,
o nr_operation Nr_Operation,
o Nr_Options PARAMETER BUNDLE,
o idu_buffer OCTET STRING,
o form_complete_pidu BOOLEAN,
-- if TRUE the implementation will attempt to form a complete PIDU
o include_data_in_token BOOLEAN,
-- if TRUE, data provided in idu_buffer will be included in the
-- generated token; if FALSE, the data will not be included
o Request_Features PARAMETER BUNDLE
-- the type of the evidence that is requested;
-- policy under which the returned evidence should be generated;
-- the recipients that are supposed to send back an evidence;
-- the recipients that should receive the requested evidence;
-- an indicator include_received_token_in_evidence:
-- if TRUE, the evidence token incorporating the request will be
-- included in the data for which recipients will generate
-- evidence; if FALSE, evidence will be generated using only
-- the data (and not the token incorporating the request).
o additional_protection BOOLEAN -- (see Section 2.3.2.4)
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o token OCTET STRING,
o evidence_check OCTET STRING,
-- present only if an evidence is requested. Consists of data to
-- be used to verify the requested token(s) (if any) when they are
-- received.
Description 🦋
this operation generates a non-repudiation token tied to the data in an input buffer. There are two kinds of operations you can do with the Nr_Operation parameter:
- a) generate a token that has either an evidence only, an evidence request only, or both an evidence and an evidence request 🎀
- b) generate a response token for some recipients that includes an evidence made in response to a request (here,
idu_bufferis where you put the request token you received) 💌
you can ask for complete evidence to be generated 🫶 that might succeed or fail. If it fails, you can make a follow-up call to Form_Complete_PIDU 🌈
2.3.3.5. IDUP_EV_SingleBuffer_Verify call
okay bestie, this is the call where you check that a token's evidence is legit and unwrap what's inside 🕵️♀️✨
Inputs:
o env_handle ENVIRONMENT HANDLE,
o token OCTET STRING,
o external_idu_buffer OCTET STRING
-- if not present within the token
o evidence_check OCTET STRING,
-- present only if the input token is a response to a previous
-- request for evidence (this parameter is used to validate that
-- evidence).
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o Nr_Options PARAMETER BUNDLE,
o Originator_Information PARAMETER BUNDLE,
o Request_Features PARAMETER BUNDLE,
o trusted_time_stamping_time INTEGER OPTIONAL,
-- present for informational purposes only
o complete_evidence_before INTEGER OPTIONAL,
-- if the major status code that is returned is
-- IDUP_S_INCOMPLETE, IDUP_Form_Complete_PIDU should be called
-- with the same token before this time.
-- This may be required, for example, in order to insure that
-- the time skew between the evidence generation time and
-- the trusted time service's countersignature on the evidence
-- falls within the interval allowed by the current NR policy.
o complete_evidence_after INTEGER OPTIONAL,
-- if the major status code that is returned is
-- IDUP_S_INCOMPLETE, IDUP_Form_Complete_PIDU should be called
-- with the same token after this time.
-- This may be required, for example, to insure that all
-- authorities involved in generating the evidence have passed
-- the last time at which the current NR policy allows them to
-- repudiate their keys.
o encapsulated_idu_buffer OCTET STRING
-- if the IDU was present within the token
o additional_unprotection BOOLEAN -- (see Section 2.3.2.5)
Description:
So this one checks that an nr_token is valid and spills what's inside it 💅. If the token with the evidence came back from a partner who was answering your request, you must pass along the evidence check you got when you made that request, together with the token. No skipping this part, periodt 🙅♀️.
The output indicators are basically hints about when you should call form_complete_pidu. Check the parameter descriptions for what each one means and how to use it 🎀. Heads up: the time in complete_evidence_before can be earlier than the one in complete_evidence_after. If that happens, you'll have to call form_complete_pidu twice 😭.
Keys can get revoked or declared compromised, so the result from verify_evidence isn't always a clean "valid" or "invalid" 💀. Sometimes you get "conditionally valid" instead, depending on the policy in use. IDUP_S_INCOMPLETE comes back, for example, if:
- the interval during which the generator of the evidence may permissibly declare his key invalid has not yet expired (so the evidence could still be declared invalid later), or
- trusted time is required for verification, and the time obtained from the token is not trusted.
2.3.3.6. IDUP_EV_MultiBuffer_StartGenerate call
this is the starting gun for generating a token when your IDU comes in lots of pieces 🧩🌸
Inputs:
o env_handle ENVIRONMENT HANDLE,
o nr_operation Nr_Operation,
o Nr_Options PARAMETER BUNDLE,
o form_complete_pidu BOOLEAN,
o include_data_in_token BOOLEAN,
o idu_size INTEGER, -- (see Section 2.3.4.2)
o Request_Features PARAMETER BUNDLE
o additional_protection BOOLEAN -- (see Section 2.3.2.4)
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o initial_pidu_buffer OCTET STRING
-- may be empty (depends on underlying mechanism)
Description:
Using the security environment referenced by env_handle, set up the data structures you need to start generating a token ✨. The IDU gets supplied in multiple buffers to the IDUP_EV_Process_Buffer call). There are two kinds of operations you can do, picked with the Nr_Operation parameter 👑:
- a) generating a token that includes either an evidence only, or an evidence request only, or both an evidence and an evidence request.
- b) generating a return token for some recipients that includes an evidence generated as a response to a request. In that case, the received token gets passed into the subsequent IDUP_EV_Process_Buffer calls. The boolean include_data_in_token is ignored, because the output will always be contained in a single token. The Request_Features are also ignored in that case, at this time, to keep things simple and avoid the piggy-backing that is theoretically possible 🫶.
You can request the generation of complete evidence. That may succeed or fail 🥲. If it fails, you can make a subsequent call to Form_Complete_PIDU.
2.3.3.7. IDUP_EV_MultiBuffer_EndGenerate call
the wrap-up call, where you finally get your token or final P-IDU 🎁
Inputs:
o env_handle ENVIRONMENT HANDLE
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o final_pidu OCTET STRING,
o token OCTET STRING,
o evidence_check OCTET STRING
-- present only if an evidence is requested.
Description:
Using the security environment referenced by env_handle, hand over the requested token or the final P-IDU 💖. A token gets generated if encapsulation wasn't requested. Otherwise, you get the final P-IDU.
2.3.3.8. IDUP_EV_MultiBuffer_StartVerify call
the verify version of the starting gun 🔍🦋
Inputs:
o env_handle ENVIRONMENT HANDLE,
o token OCTET STRING,
o evidence_check OCTET STRING,
-- present only if an evidence has been previously requested.
Outputs:
o major_status INTEGER,
o minor_status INTEGER
Description:
Using the security environment referenced by env_handle, set up the data structures needed to start verifying the token 🌈. The P-IDU gets supplied in multiple buffers to the IDUP_EV_Process_Buffer call.
2.3.3.9. IDUP_EV_MultiBuffer_EndVerify call
the verify wrap-up, where you find out if everything checked out 🥹💜
Input:
o env_handle ENVIRONMENT HANDLE
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o Nr_Options PARAMETER BUNDLE,
o Originator_Information PARAMETER BUNDLE,
o Request_Features PARAMETER BUNDLE,
o trusted_time_stamping_time INTEGER OPTIONAL,
o complete_evidence_before INTEGER OPTIONAL,
o complete_evidence_after INTEGER OPTIONAL,
o idu_buffer OCTET STRING
-- if the IDU was present within the token
o additional_unprotection BOOLEAN -- (see Section 2.3.2.5)
Description:
Using the security environment referenced by env_handle, finish the verification processing on the data 🧐. Then hand the verified output parameters back to the caller, but only when the major status code is either:
GSS_S_COMPLETEorIDUP_S_INCOMPLETE
2.3.3.10. IDUP_EV_Process_Buffer call
the call you keep repeating until every buffer is done, like a playlist on repeat 🎶
Inputs:
o env_handle ENVIRONMENT HANDLE,
o input_buffer OCTET STRING
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o output_buffer OCTET STRING
-- may be zero length (depends on underlying mechanism and
-- corresponding Generate () call and options
-- (e.g., data_included_in_token)
Description:
Using the security environment referenced by env_handle, keep processing the data in input_buffer. If there's output available, it goes into output_buffer 💅. The application keeps calling this routine with new buffers of data until it has processed all the data buffers of the IDU/PIDU. Then it calls the matching End() call to finish up ✨.
2.3.4. The "GP" Calls
the "GP" calls are giving powerful, flexible, main-character energy 👑🌟. They can mix protection and unprotection services in lots of combos, but that power means a more complicated interface than either the SE or the EV calls 🤯. Plenty of the security mechanisms people use today don't need those combos, though that could change as time goes on 🔮. So the GP calls are OPTIONAL, and IDUP-conformant implementations don't need to support them 🫶. One thing to keep in mind: the structure of IDUP tokens should be such that the SE/EV and GP calls may be used interchangably by the receiver 💜.
2.3.4.1. Parameter Bundles ✨
okay so "parameter bundles" are how the GP calls get explained in the next subsections 🎀 It's just a way to make the presentation simpler and show what each call is actually for. (Heads up: specific language bindings may or may not use parameter bundles for their real calling conventions 💅)
A parameter bundle is a set of closely related parameters of a call. Either the calling application uses or can see all of them, or it uses or can see none of them. They can all be inputs, all be outputs, or a mix of both 🦋
In C, the bundle would most likely be a structure, with each parameter as a structure member. The app allocates the structure, fills in the input values, and passes the address of the structure as the bundle "parameter". On output, it reads the output members. If the app doesn't want a bundle, or it's totally fine with default input values and doesn't care about outputs, it can pass NULL as the bundle "parameter" 💖 From the implementor's side, if a bundle isn't supported (say it's for a security service the implementation doesn't have), then any non-NULL value passed as the bundle parameter gives back an error status return code 🙈
[Note that the parameter bundles given below, except where explicitly referenced by the SE and EV calls, are specific to the (optional) GP calls. Thus, these bundles need not be supported by IDUP-conformant implementations if the GP calls are not supported.]
The bundles below get used in the protection and unprotection sets of calls that come after. A parameter marked "(I)" is an input parameter, and one marked "(O)" is an output parameter. A parameter with neither marker is an input if the bundle itself is an input, and an output if the bundle itself is an output. A parameter marked "(X)" is the opposite: an output if the bundle is an input, and an input if the bundle is an output 🌈
o Mech_Specific_Info PARAMETER BUNDLE
-- actual parameters included in this bundle are defined by (and
-- specific to) the underlying mechanism
o Sensitivity PARAMETER BUNDLE,
-- actual parameters included in this bundle are defined by (and
-- specific to) the underlying mechanism, but may include
-- codified values for "Unclassified", "Secret", "Top Secret",
-- and so on
o Service_Creation_Info PARAMETER BUNDLE
-- actual parameters included in this bundle are defined by (and
-- specific to) the underlying mechanism, but it is mandatory
-- that they include at least service_id and Quality
o Service_Verification_Info PARAMETER BUNDLE
-- actual parameters included in this bundle are defined by (and
-- specific to) the underlying mechanism, but it is mandatory
-- that they include at least service_id and Quality
o Quality PARAMETER BUNDLE
o qop_algs UNSIGNED INTEGER,
o qop_algID AlgorithmIdentifier, --overrides qop_algs
o validity UNSIGNED INTEGER,
-- protection guaranteed to be valid until time specified
o policy_id OBJECT IDENTIFIER,
-- security policy under which protection is/was carried out
o allow_policy_mapping BOOLEAN,
-- determines whether mapping between policy IDs is allowed
o actual_policy_time INTEGER
-- time at which the above policy rules came into effect
o Idu_Information PARAMETER BUNDLE,
o idu_type_oid OBJECT IDENTIFIER,
o idu_type_string OCTET STRING,
o idu_title OCTET STRING,
o idu_sensitivity Sensitivity,
o pidu_type_oid OBJECT IDENTIFIER,
o pidu_type_string OCTET STRING,
o pidu_title OCTET STRING,
o pidu_sensitivity Sensitivity,
o Prot_Information PARAMETER BUNDLE,
o originator_name INTERNAL NAME,
o originator_role Originator_Role,
o idu_information Idu_Information,
o protection_time INTEGER,
o Originator_Role PARAMETER BUNDLE, -- role in organization
o domain_name INTERNAL NAME OPTIONAL,
o role PRINTABLE STRING,
o role_info_is_authenticated BOOLEAN
-- TRUE if info. is authenticated (e.g., inside a cert.)
o Special_Conditions PARAMETER BUNDLE,
o prot_oper_id INTEGER,
o form_complete_pidu BOOLEAN,
-- input to protection operations for evidence generation
o pidu_in_solic_service BOOLEAN,
-- in protection operations, used as input for service
-- solicitation to request that receiver include the
-- received PIDU when generating the response. In unprot.
-- operations, used as output to inform receiver that PIDU
-- should be included when generating the response.
o use_trusted_time BOOLEAN,
o use_untrusted_time BOOLEAN,
o mech_indep_encap_req BOOLEAN -- (see Appendix A)
o Bad_Target_Name PARAMETER BUNDLE,
o (O) bad_targ_name INTERNAL NAME,
o (O) bad_targ_status INTEGER,
-- a status flag giving the reason for rejection of
-- the name in bad_targ_name. Specified reasons include:
-- SYNTAX_INVALID (0)
-- the syntax of the name is invalid;
-- NAME_UNRECOGNIZED (1)
-- the name is not recognized;
-- NAME_AMBIGUOUS (2)
-- the name cannot be resolved;
-- ACCESS_DENIED (3)
-- access to this target is denied;
-- CERTIFICATE_NOT_FOUND (4)
-- the encryption certificate of the target could
-- not be found.
o Target_Info PARAMETER BUNDLE,
o targ_names SET OF INTERNAL NAME,
o (O) bad_targ_count INTEGER,
o (O) bad_target_names SET OF Bad_Target_Name,
o General_Service_Data PARAMETER BUNDLE,
o target_info Target_Info,
o (X) unencapsulated_token OCTET STRING,
-- zero length if encapsulation_request is TRUE
o (O) minor_status INTEGER,
Three types of protection services are defined in IDUP, and they're all pretty iconic 👑
- Perform unsolicited service, which means acting on a locally generated service request.
- Perform solicited service, which means acting on a remotely generated service request.
- Perform service solicitation, which means sending a service request to the remote end.
As an originator, applying data confidentiality with data integrity, or data origin authentication with data integrity, or proof of origin evidence, is an example of service type 1 ✨ As a target, creating a proof of delivery (i.e., receipt) evidence token because of a request from the originator is an example of service type 2 💜 And as an originator, submitting a request that one or more targets return a receipt for the data you sent is an example of service type 3 🫶
The first four parameters in the Prot_Service parameter bundle apply to all service types. The fifth parameter is used if and only if service type 2 is wanted, and parameters 6-8 are used if and only if service type 3 is wanted 🍓
o Prot_Service PARAMETER BUNDLE
o (I) prot_service_type INTEGER,
o (I) service_id OBJECT IDENTIFIER,
o (I) quality Quality, -- NULL specifies default Quality
o (I) general_service_data General_Service_Data,
o (I) service_creation_info Service_Creation_Info,
o (I) service_to SET OF INTERNAL NAME,
o (O) service_verification_info Service_Verification_Info,
o (O) service_verification_info_id INTEGER,
Also, three types of unprotection services are defined, and they're giving "receiving end" energy 🦋
- Receive unsolicited service, which means processing an unrequested, remotely generated service.
- Receive solicited service, which means processing a remotely generated response to a locally generated request.
- Receive service solicitation, which means processing a request from the remote end.
As a target, unprotecting an encrypted message, or verifying the originator's proof of origin, is an example of service type 1 🌸 As an originator, verifying a proof of delivery that you requested from a target is an example of service type 2 🧚 And as a target, receiving a request from an originator for a proof of delivery is an example of service type 3 💅
The first four parameters in the Unprot_Service parameter bundle apply to all service types. Parameters 5-6 are used if and only if service type 2 is required, and parameters 7-8 are used only if service type 3 is required ⭐
o Unprot_Service PARAMETER BUNDLE
o (O) unprot_service_type INTEGER,
o (O) service_id OBJECT IDENTIFIER,
o (O) quality Quality,
-- actual Quality specified (never NULL)
o (O) general_service_data General_Service_Data,
o (O) service_verification_info_id INTEGER,
o (I) service_verification_info Service_Verification_Info,
o (O) service_to SET OF INTERNAL NAME,
o (O) service_creation_info Service_Creation_Info,
2.3.4.2. IDUP_Start_Protect call ✨
Inputs:
o env_handle ENVIRONMENT HANDLE,
o Mech_Specific_Info PARAMETER BUNDLE,
-- NULL selects the mechanism-defined default values
o Idu_Information PARAMETER BUNDLE,
o Special_Conditions PARAMETER BUNDLE,
o encapsulation_request BOOLEAN,
o single_idu_buffer OCTET STRING,
-- non-zero length for this buffer means that Protect/End_Protect
-- won't be called (i.e., entire IDU is contained in this buffer)
o idu_size INTEGER,
-- size (in bytes) of the IDU to be protected;
-- may be "-1" signifying "UNKNOWN" (note that some mechanisms
-- may not support encapsulation in such a case)
o Target_Info PARAMETER BUNDLE,
o Services_to_Perform SET OF Prot_Service,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o midu_buffer OCTET STRING,
-- zero length if encapsulation_request is TRUE;
-- may be zero length otherwise (depends on underlying mechanism)
o pidu_buffer OCTET STRING,
-- zero length if encapsulation_request is FALSE;
-- may be zero length otherwise (depends on underlying mechanism)
Return major_status codes:
o GSS_S_COMPLETE
-- the protection process can begin (or has completed, if
-- single_idu_buffer has non-zero length).
o IDUP_S_MORE_OUTBUFFER_NEEDED
o GSS_S_CREDENTIALS_EXPIRED
o IDUP_S_NO_ENV
o IDUP_S_ENCAPSULATION_UNAVAIL
o IDUP_S_SERVICE_UNAVAIL
o IDUP_S_REQ_TIME_SERVICE_UNAVAIL
o IDUP_S_UNKNOWN_OPER_ID
o GSS_S_BAD_QOP
o IDUP_S_BAD_TARG_INFO
o GSS_S_FAILURE
Okay bestie, this is the call that kicks everything off 💖 Using the security environment pointed to by env_handle, it sets up all the data structures needed to start protecting the IDU buffers. The caller asks for specific protection services by passing the matching Prot_Service parameter bundles in Services_to_Perform. Each service can hand back a minor status code to the calling app if it needs to. 🎀
The app knows how big its IDU is and how big its buffers are, so it can be clever about it. If the whole IDU fits in one buffer, it can put everything in single_idu_buffer and skip the later IDUP_Protect() and IDUP_End_Protect() calls entirely 🧚. It can also ask for the resulting M-IDU to be encapsulated inside the token, so the token holds the entire P-IDU, instead of getting the M-IDU back separately in midu_buffer. Encapsulation isn't guaranteed though, so not every mechanism or implementation supports it. If that's the case, you'll get IDUP_S_ENCAPSULATION_UNAVAIL back and the M-IDU shows up in midu_buffer instead 🙈
Some mechanisms have multiple stages, and each stage makes a different piece of the protection. That's where prot_oper_id comes in. It tells the mechanism which stage the app is asking for right now. A good example is a mechanism that runs the signed Message Security Protocol [MSP]. Another example is a mechanism doing a digital signature in two stages, one for hashing the message and one for signing the hash. The app would run the protection calls on the IDU for stage 1, then run them on the token from stage 1 for stage 2 🔥
prot_oper_id is just an integer (1, 2, 3, ..., n, where "n" is the number of stages the mechanism defines, usually 1 or 2). The app uses it to say whether it wants stage 1 of protection or unprotection processing, or stage 2, and so on. Portable apps can pass "0" and let the mechanism pick the stage 👑. Mechanism implementers should know that they may still iterate when prot_oper_id = 0 (for example, using output as the next input, et cetera). 💀
If one or more of the targets in targ_names can't be used as a valid recipient of the P-IDU, those names get returned in bad_targ_names, with their status codes in bad_targ_status. As long as at least one target works, the call doesn't fail. It's the caller's decision to stop protecting the IDU if the usable targets aren't good enough for what they need. ✨ Also, each Prot_Service parameter bundle can carry its own targ_names list. That list gets used for that one service only, and the general list of targets is used for everything else unless a service overrides it this way 🦋
2.3.4.3. IDUP_Protect call 🌸
Inputs:
o env_handle ENVIRONMENT HANDLE,
o input_buffer OCTET STRING,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o output_buffer OCTET STRING
-- may be zero length if encapsulation_request was set to TRUE in
-- IDUP_Start_Protect() (depends on underlying mechanism)
Return major_status codes:
o GSS_S_COMPLETE
o IDUP_S_NO_ENV
o GSS_S_FAILURE
Okay so this one is the workhorse 😭 Using the security environment referenced by env_handle, it keeps the protection processing going on whatever's in input_buffer. If the underlying mechanism defines it, any resulting P-IDU or M-IDU data goes into output_buffer. The app keeps calling this over and over with new buffers until every data buffer of the IDU has been protected. Then it calls IDUP_End_Protect() to wrap things up 🎀
2.3.4.4. IDUP_End_Protect call 💜
Inputs:
o env_handle ENVIRONMENT HANDLE,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o Services_to_Perform SET OF Prot_Service,
o final_midu_buffer OCTET STRING,
-- zero length if encapsulation_request was set to TRUE in
-- IDUP_Start_Protect(), in which case pidu is used
o final_pidu_buffer OCTET STRING,
-- zero length if encapsulation_request was set to FALSE in
-- IDUP_Start_Protect(), in which case token and midu are used
Return major_status codes:
o GSS_S_COMPLETE
-- protection has successfully completed and the resulting P-IDU
-- is ready for transfer. If defined by the underlying mechanism,
-- final_midu_buffer will contain any residual M-IDU data.
o IDUP_S_MORE_OUTBUFFER_NEEDED
o IDUP_S_NO_ENV
o GSS_S_FAILURE
This is the finale of protection, bestie 🏁 Using the security environment referenced by env_handle, it finishes the protection processing on the data and puts the output in final_pidu_buffer. If encapsulation isn't used, the output goes into final_midu_buffer and the unencapsulated_token parameter for each Prot_Service instead. If a service was requested from one or more targets in Start_Protect(), and the underlying mechanism supports it, Service_Verification_Info holds whatever data the mechanism needs so a target (the unprotector of the P-IDU) can verify the service it sends back 🔍
Real talk, though: a successful IDUP_End_Protect() does NOT mean the matching unprotection calls will definitely work when the P-IDU shows up at the target. The P-IDU could get damaged in transit, for example 💀
2.3.4.5. IDUP_Start_Unprotect call 🦋
Inputs:
o env_handle ENVIRONMENT HANDLE,
o Mech_Specific_Info PARAMETER BUNDLE,
-- NULL selects the mechanism-defined default values
o single_pidu_buffer OCTET STRING,
-- non-zero length for this buffer means that IDUP_Unprotect() and
-- IDUP_End_Unprotect() will not be called (i.e., the entire P-IDU
-- (if encapsulation is used) or M-IDU (if encap. is not used)
-- is contained in this buffer)
o partial_pidu_buffer OCTET STRING,
-- may be an arbitrary-sized piece of the full pidu (if the
-- application's buffer isn't large enough to hold entire pidu).
-- Used if pidu_buffer will be input a buffer at a time (except
-- that the final buffer must be passed in final_pidu_buffer
-- rather than partial_pidu_buffer). Only one of
-- single_pidu_buffer and partial(final)_pidu_buffer can have
-- nonzero length.
o final_pidu_buffer OCTET STRING,
o Special_Conditions PARAMETER BUNDLE,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o Services_to_Receive SET OF Unprot_Service,
o Prot_Information PARAMETER BUNDLE,
o single_idu_buffer OCTET STRING,
-- if this buffer has non-zero length, then service processing has
-- been completed on the data in single_pidu_buffer
o initial_idu_buffer OCTET STRING,
-- holds any data from partial(final)_pidu_buffer which has been
-- unprotected; remaining data will be returned by Unprotect and
-- End_Unprotect as they are called with successive buffers of
-- pidu
o Service_Verification_Info PARAMETER BUNDLE,
-- used only if target is on "service_to" list in Unprot_Service
o service_verification_info_id INTEGER,
-- used only if target is on "service_to" list in Unprot_Service
Return major_status codes:
o GSS_S_COMPLETE
-- unprotection processing can begin (or has completed, if
-- single_idu_buffer has non-zero length).
o IDUP_S_INCOMPLETE
-- used only if single_idu_buffer has non-zero length.
o IDUP_S_MORE_OUTBUFFER_NEEDED
o IDUP_S_MORE_PIDU_NEEDED
o GSS_S_DEFECTIVE_TOKEN
o IDUP_S_INAPPROPRIATE_CRED
o IDUP_S_INCONSISTENT_PARAMS
o IDUP_S_DEFECTIVE_VERIF
o IDUP_S_NO_MATCH
o IDUP_S_SERVICE_UNAVAIL
o IDUP_S_REQ_TIME_SERVICE_UNAVAIL
o IDUP_S_SERV_VERIF_INFO_NEEDED
o GSS_S_CREDENTIALS_EXPIRED
o IDUP_S_NO_ENV
o IDUP_S_UNKNOWN_OPER_ID
o GSS_S_BAD_QOP
-- the qop_algs value specified in P-IDU for at least one of the
-- services is unavailable in the local mechanism, so processing
-- cannot continue.
o GSS_S_BAD_MIC
o IDUP_S_BAD_DOA_KEY
o IDUP_S_BAD_KE_KEY
o IDUP_S_BAD_ENC_IDU
o GSS_S_FAILURE
Now we're on the receiving side, bestie 📬 Using the security environment referenced by env_handle, this call sets up the data structures needed to begin unprotecting a P-IDU. The returned Services_to_Receive set tells the caller which services were applied to the P-IDU 💖
If the originator didn't use encapsulation, the receiving app has to split the received P-IDU into an M-IDU and one or more unencapsulated_token buffers itself 🧩 Those unencapsulated_token buffers get passed in as separate Unprot_Service bundles inside Services_to_Receive. They should be input before the M-IDU (in IDUP_Start_Unprotect) or after the M-IDU (in IDUP_End_Unprotect), as appropriate. The order might be dictated by where they sit in the incoming message, for example 🌈
If unprotection gets applied more than once to the same P-IDU, the calling app is responsible for remembering whether it already responded to a service solicitation. That means checking whether the requested service was already generated and sent for that P-IDU, and ignoring any repeat solicitations on unprotect 🙈
The time flags say whether to check trusted time, untrusted time, or no time at all (if both flags are FALSE) during unprotection. If the current time isn't being checked, unprotection can still succeed even if the protector's key has expired since the P-IDU was generated. That's true even when the Validity period (as specified in the Quality parameter bundle) has run out ⏰
Last but not least 👑 if the underlying mechanism supports it, and the P-IDU contains this information, the details about the originator (the entity that used the protection set of calls to generate the P-IDU) get returned in the Prot_Information parameter bundle. ✨
2.3.4.6. IDUP_Unprotect call 🎀
okay so this is the call that keeps the unprotection going 💅 you pass in your env_handle and the chunk of data in input_buffer, and it works through that piece, giving back any IDU data it produced in output_buffer (only if that's actually needed) 🦋
Inputs:
o env_handle ENVIRONMENT HANDLE,
o input_buffer OCTET STRING
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o output_buffer OCTET STRING
Return major_status codes:
o GSS_S_COMPLETE
o IDUP_S_NO_ENV
o GSS_S_FAILURE
Using the security environment referenced by env_handle, the call continues the unprotection work on the data in input_buffer, and any resulting IDU data lands in output_buffer if it's required 🫶
2.3.4.7. IDUP_End_Unprotect call ✨
this is the finale of the unprotection era 👑 it wraps everything up, and this one has a lot going on so bear with me 🙈
Inputs:
o env_handle ENVIRONMENT HANDLE,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o Prot_Information PARAMETER BUNDLE,
o Services_to_Receive SET OF Unprot_Service,
o final_idu_buffer OCTET STRING,
o Service_Verification_Info PARAMETER BUNDLE,
-- used only if target is on "service_to" list in Unprot_Service
o service_verification_info_id INTEGER,
-- used only if target is on "service_to" list in Unprot_Service
Return major_status codes:
o GSS_S_COMPLETE
-- residual IDU data will be returned in final_idu_buffer.
o IDUP_S_INCOMPLETE
o IDUP_S_MORE_OUTBUFFER_NEEDED
o GSS_S_BAD_MIC
o IDUP_S_BAD_DOA_KEY
o IDUP_S_BAD_KE_KEY
o IDUP_S_BAD_ENC_IDU
o IDUP_S_NO_ENV
o GSS_S_FAILURE
Using the security environment referenced by env_handle, it finishes off the unprotection processing on the data and hands back the right status code 🔥 any leftover IDU data shows up in final_idu_buffer, so keep an eye on that one 👀
okay now the spicy part 🌶️ if you get IDUP_S_INCOMPLETE back, none of the output parameters are fully trustworthy yet 💀 they're only conditionally valid, which means you have to call the unprotection set of functions again (ideally with a complete P-IDU, the kind IDUP_Form_Complete_PIDU makes) to get values you can actually rely on 💖 "conditionally valid" can happen when all the relevant certificates check out fine, but we aren't yet past the window where the current policy lets the authorities involved back out of their keys 🙃
if the underlying mechanism supports it, and the token actually carries this info, then the details about the originator (the entity that used the protection set of calls to make this token) come back in the Prot_Information parameter bundle ✨ it's possible this info gets left out if IDUP_Start_Unprotect() already returned it 🧚
and here's the difference that makes IDUP-GSS-API its own vibe: unlike GSS-API, there's no concept of error tokens going back and forth between sender and recipient 🦋 that's because protection and unprotection of an IDU can be split up by an indefinite amount of time, and they might not even happen on the same entity 🌸
2.4. Special-Purpose Calls 🧚
2.4.1. Relationship to GSS-API
this special-purpose call has no analog in GSS-API [RFC-2078] 🙈 its whole job is to complete a P-IDU, meaning to generate a P-IDU that can be unprotected successfully with no additional data at any time during its validity period 💜 heads up, this call may not be supported by all underlying IDUP mechanisms or implementations 🥹
2.4.2. IDUP_Form_Complete_PIDU call
Inputs:
o env_handle ENVIRONMENT HANDLE,
o single_pidu_buffer OCTET STRING,
o partial_pidu_buffer OCTET STRING,
-- an arbitrary-sized piece of the full pidu token. Used if pidu
-- will be input a buffer at a time (except that the final buffer
-- must be passed in final_pidu_buffer rather than
-- partial_pidu_buffer). Only one of single_pidu_buffer and
-- partial(final)_pidu_buffer can have nonzero length.
o final_pidu_buffer OCTET STRING,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o pidu_token_out OCTET STRING -- the augmented PIDU; may be complete
o call_again_before INTEGER,
o call_again_after INTEGER,
o trusted_time_stamping_time INTEGER -- for information only
Return major_status codes:
o GSS_S_COMPLETE
o IDUP_S_MORE_OUTBUFFER_NEEDED
o IDUP_S_INCOMPLETE
-- generation of the P-IDU is not yet complete. The application
-- should call this function again before the time given in
-- call_again_before (if not NULL), or after the time given in
-- call_again_after (if not NULL), or both (if neither are NULL).
o IDUP_S_INCONSISTENT_PARAMS
o IDUP_S_SERVICE_UNAVAIL
o GSS_S_DEFECTIVE_TOKEN
o GSS_S_FAILURE
okay this one is mainly for the evidence services 🔍 it matters when the evidence token doesn't have all the data it needs for verification, and some of that missing data might vanish between making the token and checking it, unless it gets stored inside the token 💅 Form_Complete_PIDU goes and gathers that missing info and tucks it into the token, so verification is guaranteed to work at any future time ✨
this call generates a PIDU that can be unprotected successfully with no additional data at any time during its validity period 👑 [For background information on the notion of "complete" evidence, see "CORBA Security Service v1.2 Draft D02", 18 June 1997.] 📚
using the security environment referenced by env_handle, it completes the generation of a P-IDU token and returns the right status value along with the completed token (if it's available) 🎀 this is handy for batch evidence generation on an "evidence server" 🖥️ a local machine can use the protection set of calls to fill out most of an evidence token, then send a bunch of these to a batch processor that forms the complete evidence tokens (maybe by adding a certification path, or a timestamp and signature from a timestamping authority) 🌈 on the receiving end, an application can make this call to collect everything it needs to unprotect a P-IDU (like all relevant certificates and Certificate Revocation Lists) 🫶 that way the unprotection set of operations stays entirely local, meaning they can run off-line, and they're fast ⚡
the complete P-IDU gets formed using trusted time if it's available in the environment referenced by env_handle, and it uses untrusted time or no time otherwise (depending on what's available) 🕰️
2.5. Support calls 💖
2.5.1. Relationship to GSS-API
support calls in IDUP-GSS-API work the same way they do in GSS-API [RFC-2078] 🫧 the calls described in Section 2.4 of GSS-API (including all associated parameters) stay unchanged, and then IDUP-GSS-API adds the following extra calls 🌸
2.5.2: IDUP_Acquire_cred_with_auth call
Inputs:
o desired_name INTERNAL NAME,
-- NULL requests locally-determined default
o authenticator OCTET STRING
-- string which authenticates the caller claiming to be
-- desired_name
o lifetime_req INTEGER,
-- in seconds; 0 requests default
o desired_mechs SET OF OBJECT IDENTIFIER,
-- empty set requests system-selected default
o cred_usage BIT STRING
-- actual values which can be used currently correspond to those
-- given in Section 2.1.1 (i.e.,
-- ENCRYPT_ONLY 8
-- DECRYPT_ONLY 16
-- SIGN_ONLY 32
-- VERIFY_ONLY 64
-- with the values logically OR'ed together in any desired
-- combination to restrict credential usage; OR'ing all values
-- results in NO_RESTRICTION).
-- Future possible values for this parameter are for further
-- study (note that the type of this parameter is BIT STRING
-- (rather than INTEGER as in GSS_Acquire_cred) to facilitate
-- such future expansion).
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o output_cred_handle CREDENTIAL HANDLE,
o actual_mechs SET OF OBJECT IDENTIFIER,
o actual_cred_usage BIT STRING,
o lifetime_rec INTEGER
-- in seconds, or reserved value for INDEFINITE
this call (which doesn't need to be supported by every underlying mechanism or implementation) is basically identical to GSS_Acquire_cred 🥰 the only differences are the extra input parameter "authenticator" and the extra output parameter "actual_cred_usage" 💜 the authenticator (typically a password, pass-phrase, or PIN) is what authenticates the caller claiming to be desired_name to the underlying GSS (or mechanism) code 🔐 actual_cred_usage tells you which uses are actually available for these credentials, and it's up to the caller to decide whether that's enough for what they need 🧐
implementations that can authenticate the caller some other way are encouraged to use GSS_Acquire_cred instead 💅 the ones with no other option, or the ones that want to explicitly authenticate the caller at the moment the credential is acquired, should use IDUP_Acquire_cred_with_auth (if it's supported) 🎀
the return major status codes for this call are identical to the ones for GSS_Acquire_cred 🙌 and if authentication fails (say the wrong authenticator is given for the desired_name), you get GSS_S_FAILURE back, along with an appropriate minor status code 😭
2.5.3. IDUP_Get_token_details call ✨
Okay bestie, this one is a total glow-up for token inspection 🦋 Here's the full interface:
Inputs:
o token OCTET STRING,
-- all the data to be returned shall be within the first 4 KB of
-- the token; hence, a single call is needed. It is not necessary
-- to provide the entire token when the token includes the IDU.
o mech_type SET OF OBJECT IDENTIFIER
-- input if known (typically SET will contain a single member)
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o actual_mech_type OBJECT IDENTIFIER,
o data_included_in_token BOOLEAN,
-- true if the data is encapsulated
o idu_size INTEGER,
o has_SE_protection BOOLEAN,
o has_EV_protection BOOLEAN,
o PIDU_Information PARAMETER BUNDLE,
o nr_policy OBJECT IDENTIFIER,
-- this and subsequent parameters pertain only to evidence tokens
o Nr_Options PARAMETER BUNDLE,
o Originator_Information PARAMETER BUNDLE,
o time_stamping_time INTEGER OPTIONAL
o Request_Features PARAMETER BUNDLE,
-- describes the included request, if any.
o requested_evidence_back BOOLEAN,
-- true if this is an evidence generated in response to a
-- previously-sent request
o evidence_check OCTET STRING,
-- meaningful if the boolean above is true
Return major_status codes:
o GSS_S_COMPLETE
-- input_token could be parsed for all relevant fields.
o GSS_S_CREDENTIALS_EXPIRED
o GSS_S_DEFECTIVE_TOKEN
-- the mechanism type could be parsed, but either the other fields
-- could not be determined from the input_token, or their values
-- did not correspond to valid values for that mechanism.
o GSS_S_FAILURE
-- the mechanism type was missing or corrupted.
IDUP_Get_token_details() lets an app look up the attributes of a given input token. IDUP-GSS-API tokens are meant to stay opaque to the calling app, so this function gives it a way to learn about the token without breaking that opaqueness rule 🔒 The biggest deal here is the mechanism type. The app can feed it straight into IDUP_Establish_Env() so the right environment gets set up for processing the token. 💅
If tokens are framed the way Section 3.1 of [RFC-2078] suggests (which is mandated in the Kerberos V5 GSS mechanism [RFC 1964] and the SPKM GSS Mechanism [RFC 2025]), then any mechanism implementation should be able to hand back the mech_type parameter for any uncorrupted input token. 🎀 If the mechanism implementation whose IDUP_Get_token_details() function is being called does recognize the token, it can return any further relevant information in the other token attributes, as specified. Specifically, this function can set has_SE_protection if the SE calls may be used to unprotect it, or has_EV_protection if the EV calls may be used to unprotect it, or both if both kinds of protection have been applied (so that SE or EV calls may be used in any order for unprotection). [note that GP calls, when supported, should be usable for unprotection of any IDUP token] ✨
Heads up, bestie: IDUP_Get_token_details (which need not be supported by all underlying mechanisms or implementations) only gives a hint about what's inside the token. There is no integrity check of any kind performed 🙈 No matter the token type, the only way to confirm this information is correct is to do a proper unprotection of the token.
It is recommended that IDUP callers supply a token buffer at least 4 KB in length so the desired data can easily flow across this interface 🧚
The OID of the mechanism and whether the token contains the associated data get returned. The size of the associated data also comes back, whether it's inside or outside the token, as long as it's known. [Note: data size will typically be unknown if the data was protected using multibuffer calls. A value of "-1" may be used to indicate "UNKNOWN".] 🌸
When the input token contains only an evidence generated spontaneously, the following is returned:
- the evidence type;
- the Non-Repudiation policy under which the evidence was generated;
- the name of the generator of the evidence;
- the date and time when the evidence was generated (if available);
- the date and time when it was time stamped (if available).
When the input token contains only an evidence generated in response to a request from another entity, the following additional information is returned:
- an indicator to state that this evidence relates to a request;
- a string significant for the requester that will allow him to check whether the answer corresponds to the requested evidence.
When the input token only contains a request, the following is returned:
- the name of the requestor of the evidence,
- the date and time when the request was made,
- the evidence type to send back,
- the non-repudiation policy under which the evidence to send back should be generated,
- the names of the recipients which should generate and distribute the requested evidence,
- the names of the recipients to whom the requested evidence should be sent after it has been generated.
When the input token contains both evidence and a request, an indicator is returned describing whether the new evidence should be generated using only the data in the input token, or using both the data and the evidence in the input token. 🦋
When the input token contains only CONF and DOA services, the PIDU_Information bundle is returned. Other relevant parameters (such as idu_size and time_stamping_time) may also be returned if this data is available. 💜
2.5.4. IDUP_Get_policy_info call ✨
Next up, the policy lookup 📜
Inputs:
o policy_id OBJECT IDENTIFIER
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
o policy_version INTEGER,
o policy_effective_time INTEGER,
o policy_expiry_time INTEGER,
o supported_services SET OF Service_Descriptor,
-- services supported by this particular policy_id (equal to the
-- intersection of the services supported by the mechanisms
-- listed in supported_mechanisms)
o supported_mechanisms SET OF Mechanism_Descriptor
-- mechanisms supported by this particular policy_id
Return major_status codes:
o GSS_S_COMPLETE
-- policy_id recognized; all relevant fields have been returned.
o GSS_S_FAILURE
-- the policy_id was not recognized.
This call (which need not be supported by all underlying mechanisms or implementations) lets the app pull up info about a given policy_id 🌈 Policies define the following:
- rules for the protection of IDUs, such as trusted third parties which may be involved in P-IDU generation, the roles in which they may be involved, and the duration for which the generated P-IDU is valid;
- rules for the unprotection of P-IDUs, such as the interval during which a trusted third party may legitimately declare its key to have been compromised or revoked; and
- rules for adjudication, such as which authorities may be used to adjudicate disputes.
The policy itself may be used by an adjudicator when resolving a dispute. For example, the adjudicator might refer to the policy to determine whether the rules for generation of the P-IDU have been followed. ⚖️
The following parameter bundles are associated with this call.
o Service_Descriptor PARAMETER BUNDLE,
o service_type OBJECT IDENTIFIER,
o service_validity_duration INTEGER,
o must_use_trusted_time BOOLEAN
o Mechanism_Descriptor PARAMETER BUNDLE,
o mechanism_type OBJECT IDENTIFIER,
o Authority_List PARAMETER BUNDLE,
o maximum_time_skew INTEGER
-- maximum permissible difference between P-IDU generation
-- time and the time of countersignature from a time
-- service (if required). This parameter is unused if
-- trusted time is not required.
o Authority_List PARAMETER BUNDLE,
o authority_name INTERNAL NAME,
o authority_role OCTET STRING,
o last_revocation_check_offset INTEGER
-- may be 0, greater than 0, or less than 0. The value of
-- this parameter is added to P-IDU generation time to
-- get latest time at which the mechanism will check to
-- see if this authority's key has been revoked.
Here's an example of the last parameter in Authority_List in action 🎀 If an authority has a defined last_revocation_check_offset of negative one hour, then all revocations taking effect earlier than one hour before the generation of a P-IDU will render that P-IDU invalid. No revocation taking place later than one hour before the generation of the P-IDU will affect the P-IDU's validity. 🫶
Also, both the maximum_time_skew and the last_revocation_check_offset values are given in minutes ⏰
2.5.5. IDUP_Cancel_multibuffer_op call ✨
Last one in this batch: cancelling a multibuffer op 🛑
Inputs:
o env_handle ENVIRONMENT HANDLE,
Outputs:
o major_status INTEGER,
o minor_status INTEGER,
Return major_status codes:
o GSS_S_COMPLETE
-- operation cancelled; state purged.
o GSS_S_FAILURE
-- unable to cancel operation; state retained.
This call (which need not be supported by all underlying mechanisms or implementations) lets the app cancel a multibuffer operation before it finishes normally. For example, that could happen after calling Start_operation and zero or more Process_operation, but before calling End_operation 💅 When it succeeds, this call purges any internal state information that would have been used to keep processing the full set of multibuffer calls. 🧹
3. Related Activities ✨
To implement the IDUP-GSS-API on top of existing, emerging, and future security mechanisms, the following is necessary:
- object identifiers must be assigned to candidate IDUP-GSS-API mechanisms and the name types which they support; and
- concrete data element (i.e., token and parameter bundle) formats must be defined for candidate mechanisms.
Calling applications must implement formatting conventions which will enable them to tell IDUP-GSS-API P-IDUs apart from other IDUs in their environment 🔍
Concrete language bindings are required for the programming environments in which the IDUP-GSS-API is to be employed. 🌍
4. Acknowledgments 🫶
Many thanks are due to Tim Moses and Dhanya Thakkar of Entrust Technologies, Denis Pinkas of Bull, and David Kurn of Tandem Computers for a number of helpful comments and contributions 💖
5. Security Considerations 🔥
Security issues are discussed throughout this memo. Security is literally everywhere in this doc, so read every section like it matters, because it does 💀🔐
6. REFERENCES 📚
[MSP] U.S. National Security Agency, "Message Security Protocol", Secure Data Network System SDN.701, March 1994.
[RFC-1421] Linn, J., "Privacy Enhancement for Internet Electronic Mail: Part I: Message Encryption and Authentication Procedures", RFC 1421, February 1993.
[RFC-2078] Linn, J., "Generic Security Service Application Program Interface, Version 2", RFC 2078, January 1997..
[RFC 1964] Linn, J, "The Kerberos Version 5 GSS-API Mechanism", RFC 1964, June 1996.
[RFC 2025] Adams, C., "The Simple Public-Key GSS-API Mechanism (SPKM)", RFC 2025, October 1996.
[ISO/IEC] 2nd ISO/IEC CD 13888-1, "Information technology - Security techniques - Non-repudiation - Part 1: General Model", ISO/IEC JTC 1/SC 27, May 30, 1995
7. Author's Address 💌
Carlisle Adams
Entrust Technologies
750 Heron Road, Suite E08,
Ottawa, Ontario, CANADA K1V 1A7
Phone: +1 613.247.3180
EMail: cadams@entrust.com
APPENDIX A: MECHANISM-INDEPENDENT TOKEN FORMAT 🎀
Okay so this appendix is all about how IDUP-GSS-API tokens get the mechanism-independent level of encapsulating representation, the one described in Section 3.1 of GSS-API [RFC-2078]. That representation includes an identifier for the mechanism type that gets used when the tokens are processed. Designers of IDUP-GSS-API implementations on top of different mechanisms SHOULD use that octet format, so tokens can be read unambiguously by IDUP-GSS-API peers. 💅
It's recognized, though, that peers which aren't using IDUP for specific IDU protection and unprotection protocols might need the encapsulating representation left out for interoperability. (In that case, the underlying mechanism has to provide some kind of internal or external identification so it can recognize its own tokens.) When the mechanism-independent level of encapsulating representation isn't wanted, callers SHOULD set mech_indep_encap_req to FALSE. Note that some underlying mechanisms may default this parameter to FALSE. 🫶
For purely descriptive purposes, the following simple ASN.1 structure is used to show how the token and tag objects relate to each other. For interoperability, though, token and tag encoding shall be performed using the concrete encoding procedures described in Section 3.1 of GSS-API [RFC-2078]. 🧚
-- top-level token definition to frame different mechanisms
IDUP-GSS-API DEFINITIONS ::=
BEGIN
MechType ::= OBJECT IDENTIFIER
Token ::= [APPLICATION 0] IMPLICIT SEQUENCE {
thisMech MechType,
token ANY DEFINED BY thisMech
-- contents mechanism-specific
}
END
APPENDIX B: EXAMPLES OF IDUP USE 🦋
This appendix is full of examples of using IDUP to do IDU protection and unprotection. ✨ Please don't read these as the only way to build IDUP-GSS-API functions on a given underlying technology, or as strict rules that implementations have to follow. They also don't show off every single IDUP-GSS-API feature, so don't panic if yours isn't here. 🌸
Most of the examples below only show the CONF/DOA protection services. ngl, the tricky bit is when both CONF/DOA and Evidence services are needed. Then calling applications can either chain a series of SE and EV calls, or use the GP calls (when those are supported). The chained approach means more calls, like using SE calls to protect some data and then feeding that token into the EV calls to add evidence. Some callers find this way more appealing than coding to the GP calls, because the SE/EV interface is simpler. 💖 Depending on the underlying mechanism, a series of SE/EV calls might produce one token that can be unprotected with the SE and EV calls in any order (for example, if it's a single ASN.1 SEQUENCE that holds all the protection services at one level). Or the series might produce a token that can only be unprotected in the reverse order of protection, because each SE/EV output token got embedded in the token of the next call. The IDUP_Get_token_details call can help callers work out how to unprotect any token they receive. 🔍
B.1. Simple Mechanism, Single Buffer
Let's start with the simplest possible case. Picture an underlying IDUP mechanism that only does straightforward encryption/decryption and signing/verification, using public-key techniques. None of the other possible services are supported, such as creating proof-of-origin evidence, requesting proof-of-delivery evidence, or using trusted time. PEM[RFC-1421] is one example of a mechanism that fits this description. Also (just to keep things simple), assume the calling application chooses encapsulation during IDU protection. 🍓
This kind of mechanism would probably use the "SE" set of IDUP-GSS-API calls, so the relevant IDUP mechanism document would specify the following parameter bundle uses and defaults. 🎀
SENDER:
Set
env_handle = environment handle in use;
idu_buffer = data buffer;
Target_Info.targ_names = receiver names;
Protect_Options = as necessary;
Call
IDUP_SE_SingleBuffer_Protect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
Target_Info.Bad_Targ_Name,
(as required) for more detailed information.
Send
Output parameter pidu_buffer to receiver.
RECEIVER (any parameters not listed below are given the value NULL):
Set
env_handle = environment handle in use;
pidu_buffer = received data buffer;
Call
IDUP_SE_SingleBuffer_Unprotect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
(as required) for more detailed information
Utilize
PIDU_Information.Protect_Options.Protect_Operation,
(to determine which services were applied by the originator)
PIDU_Information.Protect_Options.sign_qop_alg / enc_qop_alg,
(to determine the corresponding qualities of the services)
Prot_Information.originator_name,
(to determine the name of the originator)
Prot_Information.protection_time,
(to determine when the IDU was protected)
idu_buffer
(to retrieve the unprotected data).
B.2. Simple Mechanism, Single Buffer (Again)
This is a little twist on the simplest case. Everything is the same as the previous scenario, except this time the "GP" calls get used. 🌈
The relevant IDUP mechanism document would specify the following parameter bundle uses and defaults. 🧁
Mech_Specific_Info
- NOT USED (the only acceptable input, therefore, is NULL)
Idu_Sensitivity
- NOT USED (the only acceptable input, therefore, is NULL)
Service_Creation_Info
- NOT USED (the only acceptable input, therefore, is NULL)
Service_Verification_Info
- NOT USED (the only acceptable input, therefore, is NULL)
Quality
- the qop_algs parameter must be supported, with a suitable DEFAULT value specified;
- suitable DEFAULT values for validity, policy_id, and allow_policy_mapping must be specified (it may be an implementation option as to whether these parameters are explicitly modifiable by the calling application, or whether NULLs are the only acceptable input)
Idu_Information
- the idu_type parameter must have a value representing a suitable IDU type (for example, in PEM a value representing the string "RFC822" or some other valid "Content-Domain" would be used), with a suitable DEFAULT value specified;
- the idu_title parameter is NOT USED (the only acceptable input, therefore, is NULL)
Prot_Information
- the originator_name and idu_type (in Idu_Information) parameters are read from the encapsulating information and output by IDUP_Start_Unprotect;
- all other parameters are NOT USED (and therefore NULL)
Special_Conditions
- NOT USED (the only acceptable input, therefore, is NULL)
Target_Info
- this bundle is used as described in IDUP; no DEFAULT values are specified
General_Service_Data
- the unencapsulated_token parameter is used if encapsulation_request is FALSE;
- the minor_status parameter is used to return minor status values as specified by the mechanism document
Prot_Service
- the prot_service_type parameter may have a value of "1" ("perform unsolicited service") or NULL (which specifies the DEFAULT value of "1");
- the service_id parameter must have a value representing "PER_CONF" or "PER_DOA";
- the parameters Service_Creation_Info, service_to, Service_Verification_Info, and service_verification_info_id are NOT USED (and therefore NULL)
Unprot_Service
- the unprot_service_type parameter will always have a value of "1" ("receive unsolicited service");
- the service_id parameter will have a value representing "REC_CONF" or "REC_DOA";
- the parameters service_verification_info_id, Service_Verification_Info, service_to, and Service_Creation_Info, are NOT USED (and therefore NULL)
Assuming the calling application only has a single buffer of data to protect or unprotect, the sender and receivers must carry out the following sequence of operations (after the environment has been set up). 🎉
SENDER (any parameters not listed below are given the value NULL):
Set
env_handle = environment handle in use;
encapsulation_request = TRUE;
single_idu_buffer = data buffer;
Target_Info.targ_names = receiver names;
P_Services.Prot_Service_1.service_id = PER_CONF;
P_Services.Prot_Service_2.service_id = PER_DOA;
Call
IDUP_Start_Protect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
Target_Info.bad_targ_names / Target_Info.bad_targ_status,
P_Services.Prot_Service_1.General_Service_Data.minor_status,
P_Services.Prot_Service_2.General_Service_Data.minor_status
(as required) for more detailed information.
Send
Output parameter pidu_buffer to receiver.
RECEIVER (any parameters not listed below are given the value NULL):
Set
env_handle = environment handle in use;
single_pidu_buffer = received data buffer;
Call
IDUP_Start_Unprotect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
R_Services.Unprot_Service_1.General_Service_Data.minor_status,
R_Services.Unprot_Service_2.General_Service_Data.minor_status
(as required) for more detailed information
Utilize
R_Services.Unprot_Service_1/2.service_id,
(to determine which services were applied by the originator)
R_Services.Unprot_Service_1/2.Quality,
(to determine the corresponding qualities of the services)
Prot_Information.originator_name,
(to determine the name of the originator)
single_idu_buffer
(to retrieve the unprotected data).
B.3. Simple Mechanism, Multiple Buffers 📦✨
okay so bestie, next level! 💅 We're taking the simple IDUP mechanism from B.2 above and feeding it multiple data buffers. The main case is signing a big data file 🗂️, and for this example the calling application is not using encapsulation 🙈.
The parameter bundle uses and defaults are the same as in B.2. above, so you already know the setup 🫶
The sender side goes like this 🚀
SENDER (any parameters not listed below are given the value NULL):
Set
env_handle = environment handle in use;
encapsulation_request = FALSE;
P_Services.Prot_Service.service_id = PER_DOA;
Call
IDUP_Start_Protect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
P_Services.Prot_Service.General_Service_Data.minor_status
(as required) for more detailed information.
For each buffer of input data:
Set
input_buffer = buffer
Call
IDUP_Protect() with above input parameter
Check
major_status. If not GSS_S_COMPLETE, check
minor_status
Call
IDUP_End_Protect()
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
P_Services.Prot_Service.General_Service_Data.minor_status
(as required) for more detailed information.
Send
P_Services.Prot_Service.General_Service_Data.unencapsulated_token,
and the file for which the signature was calculated (if required),
to receiver.
Then the receiver does the mirror image 🪞💖
RECEIVER (any parameters not listed below are given the value NULL):
Set
env_handle = environment handle in use;
R_Services.Unprot_Service_1.General_Service_Data.
unencapsulated_token = received unencapsulated token;
Call
IDUP_Start_Unprotect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
R_Services.Unprot_Service_1.General_Service_Data.minor_status,
(as required) for more detailed information
For each buffer of input data:
Set
input_buffer = buffer
Call
IDUP_Unprotect() with above input parameter
Check
major_status. If not GSS_S_COMPLETE, check
minor_status
Call
IDUP_End_Unprotect()
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
R_Services.Unprot_Service_1.General_Service_Data.minor_status,
(as required) for more detailed information.
Utilize
R_Services.Unprot_Service_1.service_id,
(to determine which service was applied by the originator; note
that Unprot_Service_2 will have NULL in unprot_service_type
to indicate that it is not used)
R_Services.Unprot_Service_1.Quality,
(to determine the corresponding quality of the service)
Prot_Information.originator_name, (from IDUP_Start_Unprotect)
(to determine the name of the signer)
major_status (from IDUP_End_Unprotect)
(to determine pass/fail status of signature verification).
B.4. More Sophisticated Mechanism, Small Application Buffers ✨
okay so now we level up 🔥 let's look at a more sophisticated IDUP mechanism paired with a calling app that only has small data buffers 🧚 the example is a very small e-mail message getting encrypted for a pretty big receiver list (R) 💌 some of those folks (r) are asked to send proofs of receipt to another group (L), and L includes the originator 🫶 to keep things from getting too messy, the originating app uses encapsulation again, same as before.
The uses and defaults for each parameter bundle get spelled out in the relevant IDUP mechanism document, and it goes like this 💜
Mech_Specific_Info: NOT USED, so the only acceptable input is NULL 🙈Idu_Sensitivity: NOT USED, so the only acceptable input is NULL 🙈Service_Creation_Info: used to create "proof of delivery" evidence, but the actual structure is opaque to the calling application 🎀Service_Verification_Info: used to verify "proof of delivery" evidence, but the actual structure is opaque to the calling application 🎀Quality:- the
qop_algsparameter must be supported, with a suitable DEFAULT value specified 💅 - suitable DEFAULT values for
validity,policy_id, andallow_policy_mappingmust be specified. It's an implementation option whether the calling app can explicitly modify these, or whether NULLs are the only acceptable input 🤷♀️
- the
Idu_Information:- the
idu_typeparameter must have a value representing a suitable IDU type, with a suitable DEFAULT value specified ✨ - the
idu_titleparameter must have a value representing a suitable IDU title, with a suitable DEFAULT value specified ✨
- the
Prot_Information: theoriginator_name,protection_time, andidu_type/idu_title(inIdu_Information) parameters get read from the contained header info and output byIDUP_Start_Unprotect📬Special_Conditions:- the
prot_oper_idparameter is NOT USED, so the only acceptable input is NULL 🙈 - the calling app can pick trusted or untrusted time, with a suitable DEFAULT value specified ⏰
- the
Target_Info: this bundle gets used as described in IDUP, and no DEFAULT values are specified 🎯General_Service_Data:- the
unencapsulated_tokenparameter is used ifencapsulation_requestis FALSE 🍓 - the
minor_statusparameter is used to return minor status values, as specified by the mechanism document 💜
- the
Prot_Service:- the
prot_service_typeparameter may have a value of"1"("perform unsolicited service"),"2"("perform solicited service"),"3"(perform service solicitation), or NULL (which specifies the DEFAULT value of"1") 🦋 - the
service_idparameter must have a value representing"PER_CONF","PER_DOA","PER_POO", or"PER_POD"🌈 - the parameters
Service_Creation_Info,service_to,Service_Verification_Info, andservice_verification_info_idget used when the IDUP operation requires them 🧠
- the
Unprot_Service:- the
unprot_service_typeparameter may have a value of"1"("receive unsolicited service"),"2"("receive solicited service"), or"3"(receive service solicitation) 🌸 - the
service_idparameter will have a value representing"REC_CONF","REC_DOA","REC_POO", or"REC_POD"🌸 - the parameters
service_verification_info_id,Service_Verification_Info,service_to, andService_Creation_Infoget used when the IDUP operation requires them 🧠
- the
Now the sender side, where any parameter not listed is just NULL 💅
SENDER (any parameters not listed below are given the value NULL):
Set
env_handle = environment handle in use;
Idu_Information.idu_type = value for "e-mail document";
Idu_Information.idu_title = "Contract 1234";
Special_Conditions.use_trusted_time = TRUE;
encapsulation_request = TRUE;
single_idu_buffer = very small e-mail message;
Target_Info.targ_names = receiver names (R);
Prot_Service_1.prot_service_type = "1";
Prot_Service_1.service_id = PER_CONF;
Prot_Service_2.prot_service_type = "3";
Prot_Service_2.service_id = PER_POD;
Prot_Service_2.General_Service_Data.Target_Info.targ_names
= "receipts from" list (r);
Prot_Service_2.service_to = "receipts to" list (L);
P_Services.Prot_Service_1 = Prot_Service_1;
P_Services.Prot_Service_2 = Prot_Service_2;
Call
IDUP_Start_Protect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE,
while major_status == IDUP_S_MORE_OUTBUFFER_NEEDED
Save
pidu_buffer,
Call
IDUP_Start_Protect() (to get next portion of pidu_buffer)
Check
major_status,
minor_status,
Target_Info.bad_targ_names / Target_Info.bad_targ_status,
P_Services.Prot_Service_1.General_Service_Data.minor_status,
P_Services.Prot_Service_2.General_Service_Data.minor_status
(as required) for more detailed information.
Save
Prot_Service_2.Service_Verification_Info,
Prot_Service_2.service_verification_info_id
Send
All saved buffers of pidu_buffer to receiver list (R).
Next up is the receiver side 📫 this bit is where all the good stuff happens, so pay attention bestie 👀
RECEIVER (ON RECEIVER LIST (R)):
(any parameters not listed below are given the value NULL)
Set
env_handle = environment handle in use;
partial_pidu_buffer = initial buffer of received p-idu;
Call
IDUP_Start_Unprotect() with above input parameters
While major_status == IDUP_S_MORE_PIDU_NEEDED,
Set
partial_pidu_buffer = next buffer of p-idu
Call
IDUP_Start_Unprotect()
Check
major_status,
minor_status,
R_Services.Unprot_Service_1.General_Service_Data.minor_status,
R_Services.Unprot_Service_2.General_Service_Data.minor_status,
(as required) for more detailed information
Save
initial_idu_buffer (if non-empty)
Set
input_buffer = remaining p-idu buffer
Call
IDUP_Unprotect() with above input parameter
Check
major_status. If not GSS_S_COMPLETE, check
minor_status
Save
output_buffer
Call
IDUP_End_Unprotect()
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
R_Services.Unprot_Service_1.General_Service_Data.minor_status,
R_Services.Unprot_Service_2.General_Service_Data.minor_status,
(as required) for more detailed information.
Utilize
R_Services.Unprot_Service_1/2.service_id,
(to determine which services were applied by the originator)
R_Services.Unprot_Service_1/2.Quality,
(to determine the corresponding qualities of the service)
Prot_Information.originator_name/protection_time and
Prot_Information.Idu_Information.idu_type/idu_title,
(from IDUP_Start_Unprotect) (to determine originator info.)
R_Services.Unprot_Service_2.General_Service_Data.Target_Info.
targ.names, (to determine if rec. is in "receipts from" (r))
Service_Verification_Info/service_verification_info_id
(to determine if receiver is in "receipts to" list (L))
If receiver is in "receipts from" list (r)
Save
R_Services.Unprot_Service_2.service_to,
R_Services.Unprot_Service_2.Service_Creation_Info
If receiver is in "receipts to" list (L)
Save
Service_Verification_Info,
service_verification_info_id
RECEIVER (ON "RECEIPTS FROM" LIST (r)):
(procedure to generate receipt)
Set
env_handle = environment handle in use;
Target_Info.targ_names = service_to
Prot_Service_1.prot_service_type = "2";
Prot_Service_1.service_id = "PER_POD";
Prot_Service_1.Service_Creation_Info = Service_Creation_Info;
P_Services.Prot_Service_1 = Prot_Service_1
Call
IDUP_Start_Protect() with above input parameters
Check
major_status. If not GSS_S_COMPLETE, check
minor_status,
P_Services.Prot_Service_1.General_Service_Data.minor_status
(as required) for more detailed information.
Send
pidu_buffer to "receipts to" list (L)
RECEIVER (ON "RECEIPTS TO" LIST (L)):
(procedure to process received receipt)
Set
env_handle = environment handle in use;
single_pidu_buffer = received p-idu buffer (if it fits in a single
buffer; otherwise use partial_pidu_buffer and make multiple
calls, as above)
Call
IDUP_Start_Unprotect() with above input parameters
If major_status == IDUP_S_SERV_VERIF_INFO_NEEDED
Utilize
R_Services.Unprot_Service_1.service_verification_info.id
(to assist in locating necessary Service_Verification_Info)
Set
R_Services.Unprot_Service_1.Service_Verification_Info
= Service_Verification_Info
Call
IDUP_Start_Unprotect() with above input parameters
Check
major_status,
minor_status,
R_Services.Unprot_Service_1.General_Service_Data.minor_status
(as required) for more detailed information.
Utilize
R_Services.Unprot_Service_1.service_id,
(to determine that this is a "proof of delivery" evidence)
R_Services.Unprot_Service_1.Quality,
Prot_Information.originator_name, (for evidence generator info.)
major_status (to determine pass/fail status of evi. verif.).
Full Copyright Statement 💖
Copyright (C) The Internet Society (1998). All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.
This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 🫶
📦 where this page comes from
- ietf: rfc2479 1998-12
- 💖 girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms