Cryptographic system with methods for user-controlled message recovery6314190Abstract A cryptosystem is described which automatically provides an extra "message recovery" recipient(s) when an encrypted message is generated in the system. The system is typically configured such that the extra recipient or "message recovery agent" (MRA)--an entity which itself has a public key (i.e., a MRA public key)--is automatically added, under appropriate circumstances, as a valid recipient for an encrypted message created by a user. In a corporate setting, for example, the message recovery agent is the "corporate" message recovery agent designated for that company (firm, organization, or other group) and the user is an employee (or member) of that company (or group). In operation, the system embeds a pointer (or other reference mechanism) to the MRA public key into the public key of the user or employee, so that encrypted messages sent to the company's employees from outside users (e.g., those individuals who are not employees of the company) can nevertheless still be recovered by the company. Alternatively, the MRA public key itself can be embedded within the public key of the employee or user (i.e., a key within a key), but typically at the cost of increasing the storage requirement of the user's key. By including in the user's key (e.g., an employee) a pointer to a message recovery agent's key (or the MRA key itself), the system provides a mechanism for assisting a user outside a group (e.g., a user who is outside a particular company) with the task of including in an automatic and non-intrusive manner the key of an additional recipient, such as one intended for message recovery. Claims What is claimed is: Description REFERENCE TO MICROFICHE APPENDIX
Keys Shows an iconic representation of the key along with the user name
and e-mail
address of the owner.
Val- Indicates the level of confidence that the key actually belongs to
the alleged
id- owner. The validity is based on who has signed the key and how well
the user
ity trusts the signer(s) to vouch for the authenticity of a key. The
public keys the
user signs himself or herself have the highest level of validity,
based on the
assumption that the user will only sign someone's key if he or she is
totally
convinced that it is valid. The validity of any other keys, which the
user has
not personally signed, depends on the level of trust the user has
granted to any
other users who have signed the key. If there are no signatures
associated
with the key, then it is not considered valid and a message
indicating this fact
appears whenever the user employs the key.
Trust Indicates the level of trust the user has granted to the owner of the
key to serve
as an introducer for the public keys of others. This trust comes into
play when
the user is unable to verify the validity of someone's public key for
himself or
herself and instead elects to rely on the judgement of other users
who have
signed the key. When the user receives a public key from someone that
has
been signed by another of the user's keys on the user's public
keyring, the
level of authenticity is based on the trust the user has granted to
the owner of
that key. When the user creates a set of keys, they are considered
implicitly
trustworthy, as represented by striping in the trust and validity
bars. The user
assigns a level of trust (either Complete, Marginal or Untrusted) in
a
"Properties" dialog box.
Crea- Shows the date when the key was originally created. The user can
sometimes
tion make an assumption about the validity of a key based on how long it
has been
in circulation. If the key has been in use for a while, it is less
likely that
someone will try to replace it because there are many other copies in
circulation.
Size Shows the number of bits used to construct the key. Generally, the
larger the
key, the less chance that it will ever be compromised. However,
larger keys
require slightly more time to encrypt and decrypt data than do
smaller keys.
When the user creates a DSS/Diffie-Hellman key, there is one number
for the
DSS portion and another number for the Diffie-Hellman portion.
From the PGPkeys window 500, the employee or user can generate a new key pair from a using a Key Generation Wizard that guides the user through the process. Specifically, the Key Generation Wizard is invoked by selecting a "New Key" menu choice 510 from the PGPkeys window, as shown in FIG. 5B. In response, the system displays Key Generation Wizard 520, as FIG. 5C illustrates. At the outset, the Key Generation Wizard 520 provides some introductory information on its opening page or pane. The user proceeds by clicking the "Next" button to advance the dialog to the next dialog page. In response, the system displays a new page for the Key Generation Wizard (now 520a), as FIG. 5D illustrates. Here, the Key Generation Wizard asks the user to enter his or her user name and e-mail address. The user clicks "Next" to advance to the next dialog box, which is shown in FIG. 5E. The Key Generation Wizard (now 520b) then asks the user to choose a key type: either DSS/Diffie-Hellman or RSA. The user clicks Next to advance to the next dialog box, which is shown in FIG. 5F. Key Generation Wizard (now 520c) asks the user to specify a size for the new keys. The user can select a key size (from 768 to 3072) or enter any key size from (from 768 to 4096). RSA keys are limited to 2048 bits in order to maintain compatibility with older versions of the system. The key size corresponds to the number of bits used to construct the digital key. The larger the key, the less chance that someone will ever be able to crack it, but the longer it will take to perform the decryption and encryption process. The user clicks Next to advance to the next dialog box. As shown in FIG. 5G The Key Generation Wizard (now 520d) asks the user to indicate when the key pair should expire. Here, the user indicates when the keys should expire. The user can select either the default selection which is "never", or can enter a specific number of days after which the keys will expire. For the latter, the user may want to create a special set of keys that he or she plans to use for a limited period of time. In this case, when the public key expires it can no longer be used by someone to encrypt mail for the user but it can still be used to verify his or her digital signature. Similarly, when the private key expires, it can still be used to decrypt mail that was sent to the user before the public key expired; it can no longer be used to sign mail for others, however. The user clicks Next to advance to the next dialog box. As shown in FIG. 5H, the Key Generation Wizard (now 520e) asks the user to enter a passphrase. In the "Passphrase" entry box, the user enters the string of characters or words he or she wants to use to gain exclusive access to the user's private keys. A passphrase should generally contain multiple words and may include spaces, numbers, and other printable characters. The longer the passphrase, and the wider the variety of characters it contains, the more secure it is. The user clicks Next to advance to the next dialog box. As shown in FIG. 5I, the Key Generation Wizard (now 520f) has begun the key generation process. When done with this step, the Key Generation Wizard indicates that the actual key generation has occurred. The user clicks Next to advance to the next dialog box. As shown in FIG. 5J, the Key Generation Wizard (now 520g) gives the user the opportunity to sign the new key. The user can, for instance, sign the new key with the user's older key. This is helpful when the user is creating a key with the same user name or e-mail address as a previous key. If the user is creating a new key pair for use in the user's capacity as an employee, however, the user can sign his or her new key, whereupon the system embeds the (pointer to) MRA key for the user's company (as described in further detail below). The user clicks Next to advance to the next dialog box. As shown in FIG. 5K, the Key Generation Wizard (now 520h) indicates that the user has successfully generated a new key pair and asks the user whether to send the newly-created public key to a public key server. By sending your public key to the key server, anyone will be able to get a copy of your key when they need it. After specifying whether the new public key should be sent to a key server, the user clicks Next. Now, the Key Generation process is complete, and the final wizard dialog box (shown at 520i) appears, as shown in FIG. 5L. A pair of keys representing the newly-created keys appears in the PGPkeys window, with RSA keys shown in blue and DSS/Diffie-Hellman keys shown in yellow. At this point, the user can examine the keys by checking their properties and the values associated with them. The user can modify the values, if desired (e.g., to add other user names or e-mail addresses). 4. Embedding the MRA Key (pointer) During the key generation process, the user can specify various assertions about the key pair, such as an expiration date (if any). Internally, such attributes are embedded within a key by hashing the attributes into the key's signature or ID. This approach is also employed to embed the MRA key. More particularly, in accordance with the present invention, a pointer (or other reference) to the key of the message recovery agent can, if consented to by the user, also be hashed into the signature. At the conclusion of generating a new key pair, for example, the employee or user will have signed the key pair with a digital signature which includes a hashed value identifying the key for the message recovery agent of the employee's company. In essence, this hash for the user's key points to the public key of the message recovery agent. By the employee signing his or her key this way, the employee is also providing consent for inclusion of the (pointer to) public key of the message recovery agent. The semantics for this consent are conceptually as follows: I hereby give my consent to have my e-mail be also readable by the message recovery agent which I have designated. Through the digital signature process, the employee, in essence, anoints a particular message recovery agent as being suited for being able to sometimes read the employee's messages. When the employee publishes his or her public key (e.g., by posting it to a key server), he or she also publishes a copy of the corporate message recovery agent's public key. When the public key is downloaded from the key server, a copy of the corporate message recovery agent's key is also downloaded. The key server can provide the additional key either automatically (i.e., automatically download the MRA key) or manually (i.e., require a request or acknowledgment before the key is downloaded). In this manner, when an outside user sends a message to the employee, the sender is given the opportunity of adding an extra recipient (i.e., the message recovery agent), even though the message is not being sent from within the company. Since the message recovery agent's key has, in effect, traveled along with the employee's key, the corporate message recovery agent is provided as an extra recipient in an automated manner--without requiring intervention by the sender. The actual "pointer" or reference to the recovery agent's public key can be achieved by any unambiguous means for referencing the key. In the currently preferred embodiment, a cryptographic hash of the key, such as a Message Digest (e.g., Secured Hash Algorithm (SHA), or less-preferably MD5), is preferably employed, for preventing substitution of the key (or other tampering). For a discussion of cryptographic hashes, including SHA and MD5, see e.g., the abovementioned Applied Cryptography by Bruce Schneier. The disclosures of each of the foregoing are hereby incorporated by reference. The general methodology of the present invention itself does not depend on use of a hash as (or as part of) the signature or ID. By employing a cryptographic hash or Message Digest, however, tampering is prevented, since it is computationally infeasible (given current and foreseeable hardware) to generate a key which would hash to the same ID or signature. As a further refinement, in the currently preferred embodiment the MRA hash includes a set of user-supplied strictness criteria, for allowing the sender to specify the recipient's use of the key. For example, the sender could specify that all response messages should preferably include or must include the message recovery agent as a co-recipient. The strictness criteria can specify further preferences, such as requiring use of the message recovery agent for business-related messages. Although the currently preferred embodiment employs a pointer to the message recovery agent's public key, those skilled in the art, enabled by the teachings herein, will appreciated that the actual MRA key itself may be embedded as an assertion to the employee's signed key. In this manner a download of the employee's key would automatically include a copy of the message recovery agent's key. In a preferred embodiment, however, it is preferable to simply include a pointer to the key, thereby reducing the storage requirements of the employee's key (as each copy is about 2,000 bits or more in length). 5. Automated Use of the MRA Key by an Outside User With reference to FIG. 6A, automated use of the MRA key by an outside user will now be described. Interface 600 is employed for creating and sending encrypted messages. At its top half, the interface 600 includes a list of keys 610. This list represents keys on a user's keyring (e.g., a local directory or a company wide directory of keys). At its bottom half, the interface includes a recipient list 620. The recipient list 620 indicates the intended recipient for the encrypted message. In response to the user selecting a key (e.g., the user double clicking on a key with a mouse), the system in turn selects the key and "teleports" the key to the recipient list 620. In the event that a key in the list of keys 610 is one associated with a message recovery agent, such as MRK user test key 630, additional key(s) will appear in the list. For MRK user test key 630, for instance, Message Recovery Key #1 (631) and Message Recovery Key #2 (633) are also displayed, as shown. Message Recovery Key #1 is an optional message recovery key. Message Recovery Key #2, on the other hand, is a mandatory message recovery key--that is MRK user test key 630 specifies a policy requiring user of the message recovery key. Now, when the MRK user test key 630 is selected for adding the user as an intended recipient, the key(s) of the message recovery agent are also added. This action is illustrated in FIGS. 6B-C, by the user "dragging" and "dropping" key 630. FIG. 6B illustrates the MRK user test key 630 (shown at 630a) being "dragged" over to the recipient list 620 (shown at 620a), using a mouse device. Upon the user "dropping" the MRK user test key, the MRK user test key (shown at 630b) appears in the recipient list together with keys of the associated message recovery agent: Message Recovery Key #1 (shown at 631a) and Message Recovery Key #2 (shown at 633a). In the currently preferred embodiment, this multi-key user interface approach is employed to inform the user that the message will be encrypted also for the corporate message recovery recipient or agent, in addition to any other recipient which the user has added to the recipient's list 620. Here, the user (sender) is informed of the automatically added additional recipient (i.e., corporate message recovery agent), as if the user had manually added that recipient key to the recipient list 620. The user can continue to add other recipients to the recipient list. Some of those recipients can, in turn, include automatic additional recipients or corporate recovery agent keys, which are the same as and/or different from the corporate recovery agent key previously added by the system. In the currently preferred embodiment, the user or sender is given the flexibility to delete any key from the recipient list, including even mandatory message recovery keys. In FIG. 6E, for example, the user selects Message Recovery Key #2 (shown at 633b) for deletion. Upon the user invoking "Delete" for this mandatory key, the system first warns the user that the requested deletion might violate a policy established by other keys in the recipient list, by displaying Warning dialog 640. Nevertheless, the user may proceed, whereupon the message recovery key is removed from the list, as shown in FIG. 6F. In a like manner, if desired at this point, the user can delete the other message recovery key as well. Since the other key is an "optional" key, no warning dialog would be shown. Those skilled in the art will appreciate that the foregoing interface can easily be adapted such that this user option is not provided (or that the user is not even shown that such keys are being added). Although the user might desire to delete recovery keys from personal messages, the user will still nevertheless oftentimes very much want the recovery key included, such as when the user is transacting company business (e.g., transmitting a purchase order to another company). 6. Summary of Methodology Referring now to FIG. 7, a method for message recovery using a recovery key may be summarized as follows. At step 701, at least one message recovery agent's public key(s) (i.e., public key of the MRK pair) is created for the cryptosystem, so that users of the system can selectively embed (a pointer to) the recovery key during generation of the user's key pair; the corresponding private key for the MRA (public) key is also conveniently generated at this point. Typically, the MRA key will be that of a particular company. If desired, generation of the MRK can be deferred until such times as the public key of the MRK is actually referenced (e.g., from a public key being generated for a newly-hired employee). At step 702, the system generates a key pair in response to a user's request. At shown at step 703, the user is prompted to (optionally) activate message recovery by digitally signing his/her own key, for the specific purpose of consenting to embedding the MRA key within the user's own key. In response to the user providing such consent, the cryptosystem embeds a "pointer" (i.e., handle, reference, or other unique ID), at step 704, into user's public key for referencing MRA public key. Typically, this step is performed using a cryptographic hash or message digest, for guarding against tampering. Although less space-efficient, the MRA key itself can be embedded, if desired. The underlying data structure supporting key creation at this point is a "signature specification" data structure, which may be defined as follows.
/*
The following is the data structure used to create a key; the fields
labelled "havekdecryption" and "kdecryption" determine whether it has a
recovery key associated with it.
*/
struct PGPSigSpec {
PGPContextRef cdkContext;
PGPSigSpec *next;
PGPSecKey *seckey;
PgpVersion version;
PGPByte hashtype;
PGPBoolean exportable;
PGPBoolean exportableHashed;
PGPBoolean revokable;
PGPByte extra[5]; /* I know this is 5 bytes now! */
PGPUInt32 sigExpiration; /* Timestamp for sig to expire */
PGPByte trustLevel; /* 0 for regular, 1 for trust,
> for meta */
PGPByte trustValue; /* if trustLevel > 0 */
PGPBoolean hasRegExp;
char regExp[MAXREGEXP];
/* Next ones are only used on key self-sigs */
PGPUInt32 keyExpiration; /* Timestamp for key to expire. */
PGPByte prefAlgs[20]; /* Preferred algorithms */
PGPByte havekdecryption[NR]; /* True if kdecryption has
been set */
PGPByte kdecryption[NR] [22]; /* Key additional decryption
information
*/
PGPByte havekrevocation[NR]; /* True if krevocation has
been set */
PGPByte krevocation[NR] [22]; /* Key revocation information */
DEBUG_STRUCT_CONSTRUCTOR( PGPSigSpec )
};
The last two fields of the data structure indicate whether the created key has a recovery key associated with it. Here, havekrecovery serves as a Boolean for indicating whether the current key has an associated message recovery key. Information about the message recovery key itself is stored by Krecovery, a byte array. Step 705 illustrates that, in response to a request from an "outside" user to send a message to the user (i.e., adding the user's key to a recipient list), the MRA is automatically added as an optional recipient. Here, the system finds the message recovery key subpacket, then performs a look-up operation to see whether there exists a corresponding key.
/*
* Find an additional decryption key for the given key, if one exists.
* nth tells which one to find. *pkeys is set to the number of add'l
* decryption keys, *pclass is set to the class byte associated with
* the decryption key. *pkalg and *keyid are set to the algorithm and
* keyid of the nth ADK key. Returns NULL but no error in *error if
* the ADK key is not in the specified ringset. Return *error as
* kPGPError_ItemNotFound if there are fewer than n + 1 ADKs.
*/
union RingObject *
ringKeyAdditionalRecipientRequestKey (RingObject *obj, Ringset const *set,
unsigned nth, PGPByte *pkalg, PGPKeyID *keyid,
PGPByte *pclass, unsigned *pkeys, PGPError *error)
{
RingObject *rkey; /* Additional decryption key */
PGPByte const *krpdata; /* Pointer to key decryption data */
PGPSize krdatalen; /* Length of krdata */
int critical; /* True if decryption field was critical */
unsigned matches; /* Number of adk's found */
PGPByte fingerp[20]; /* Fingerprint of adk */
PGPByte krdata[22]; /* Copy of key decryption data packet */
pgpAssert (OBJISKEY (obj));
pgpAssert (pgpIsRingSetMember (set, obj));
pgpAssert (error);
*error = kPGpError_NoErr;
if( IsntNull( pkeys ) )
*pkeys = 0;
if( IsntNull( pclass ) )
*pclass = 0;
if( IsntNull( pkalg ) )
*pkalg = 0;
if( IsntNull( keyid ) )
pgpClearMemory( keyid, sizeof( *keyid ) );
}
krpdata = ringKeyFindSubpacket (obj, set,
SIGSUB_KEY_ADDITIONAL_RECIPIENT_REQUEST, nth, &krdatalen,
&critical, NULL, NULL, &matches, error);
if (!krpdata) {
if (IsntPGPError(*error))
*error = kPGPError_ItemNotFound;
return NULL;
}
/*
* krdata is 1 byte of class, 1 of pkalg, 20 bytes of fingerprint.
* Last 8 of 20 are keyid. Make a copy because data is volatile when
* we do other operations.
*/
if (krdatalen < sizeof(krdata)) {
/* malformed packet, can't use it */
*error = kPCPError_ItemNotFound;
return NULL;
}
pgpCopyMemory (krpdata, krdata, sizeof(krdata));
/* Do we have ADK? */
rkey = ringKeyById8 (set, krdata[1], krdata + 2 + 20 - 8);
if (IsntNull (rkey)) {
if (pgpVirtMaskIsEmpty(&rkey->g.mask)) {
rkey = NULL;
} else {
ringKeyFingerprint20 (set, rkey, fingerp);
if (memcmp (fingerp, krdata + 2, 20) != 0) {
/* Have a key that matches in keyid but wrong fingerprint
rkey = NULL;
}
}
}
/* Success */
if (pkeys) {
*pkeys = matches;
}
if (pclass) {
*pclass = krdata[0];
}
if (pkalg) {
*pkalg = krdata[1];
}
if (keyid) {
pgpNewKeyIDFromRawData( krdata + 2 + 20 - 8, 8, keyid );
}
return rkey;
}
Applications can call the system to return the message recovery keys associated with a given key, as illustrated below.
/* Return the nth (0 based) additional decryption key and keyid,
if one exists.
It is an error to use an index >= K,
where K is the number of ARR key ids.
Also return the class of the ADK. The class is currently reserved
for use by PGP.
Any of the return pointers may be NULL.
Note that it is *not* safe to use the keyID returned from this function
to get the ADK to use because KeyIDs are not unique.
Instead, the keyID can be used to locate the actual key(s) with that
key id.
Then call this function again to get the ADK;
it will check the key fingerprint, which is unique.
/*
static PGPError
pgpGetIndexedAdditionalRecipientRequestKey(
PGPKeyRef basekey,
PGPKeySetRef allkeys,
PGPUInt32 nth,
PGPKeyRef* adkey,
PGPKeyID * adkeyid,
PGPByte * adclass)
{
RingSet const *ringset; /* Aurora ringset to look in */
union RingObject *keyobj; /* Aurora base key */
union RingObject *rkey; /* Aurora additional decryption key
*/
unsigned nadks; /* Number ADK's available */
PGPByte tclass; /* Class code from ADK */
PGPError error; /* Error return from Aurora */
PGPByte pkalg; /* pkalg of ADK */
PGPKeyID keyid; /* keyid of ADK */
PGPError err = kPGPError_NoErr;
PGPContextRef context;
if( IsntNull( adkeyid ) )
pgpClearMemory( adkeyid, sizeof( *adkeyid ) );
if ( IsntNull ( adclass ) )
*adclass = 0;
if ( IsntNull( adkey ) )
*adkey = NULL;
ringset = NULL;
PGPValidateKey( basekey );
PGPValidateKeySet( allkeys );
context = PGPGetKeyContext ( basekey );
error = pgpKeySetRingSet (allkeys, TRUE, &ringset);
if( IsPGPError( error ) )
return error;
keyobj = basekey->key;
rkey = ringKeyAdditionalRecipientRequestKey (keyobj, ringset, nth,
&pkalg, &keyid, &tclass, &nadks, &error);
if( IsPGPError( error ) )
{
ringSetDestroy( (RingSet *) ringset );
return error;
}
/* Success */
if ( IsntNull( adkey ) )
{
PGPKeyID keyID;
if (IsNull( rkey ) ) {
*adkey = NULL;
} else {
ringKeyID8 (ringset, rkey, &pkalg, &keyID);
err = PGPGetKeyByKeyID (allkeys, &keyID,
(PGPPublicKeyAlgorithm)pkalg, adkey);
}
}
if ( IsntNull( adkeyid ) )
{
*adkeyid = keyid;
}
if ( IsntNull( adclass ) )
*adclass = tclass;
if( IsntNull( ringset ) )
ringSetDestroy( (RingSet *) ringset );
return err;
}
Given a key, the system may return the nth (0-based) additional decryption key, if one exists.
/* Given a key, return the nth (0 based) additional decryption key, if
one exists. Also return the keyid, the class of the ADK, and the
number of ADK's for the base key. Any of the return pointers may
be NULL. */
PGPError
PGPGetIndexedAdditionalRecipientRequestKey(
PGPKeyRef basekey,
PGPKeySetRef allkeys,
PGPUInt32 nth,
PGPKeyRef * adkey,
PGPKeyID * adkeyid,
PGPByte * adclass)
{
PGPError err = kPGPError_NoErr;
PGPKeyID tempKeyID;
if ( IsntNull( adkey ) )
*adkey = NULL;
if ( IsntNull( adkeyid ) )
pgpClearMemory( adkeyid, sizeof( *adkeyid) );
if ( IsntNull( adclass ) )
*adclass = 0;
PGPValidateKey( basekey );
PGPValidateKeySet( allkeys );
err = pgpGetIndexedAdditionalRecipientRequestKey( basekey,
allkeys, nth, adkey, &tempKeyID, adclass );
if ( IsntPGPError( err ) )
{
pgpAssert( pgpKeyIDIsValid( &tempKeyID ) );
if( IsntNull( adkeyid ) )
{
*adkeyid = tempKeyID;
}
}
else
{
pgpClearMemory( adkeyid, sizeof( *adkeyid) );
}
return( err );
}
Thus once the outside user's system has obtained the MRA's public key, the MRA can be added as a recipient of the message (i.e., a copy of the message's session key is encrypted with the MRA public key). As a result of this, the encrypted message can be recovered, if needed, by the message recovery agent. Specifically, as shown in step 706, the private key of the MRA key pair can be used to decrypt the encrypted message, for recovering the original message. 7. Conclusion When a user publishes his or her public key, there has previously been no mechanism available for assisting an outside user with the task of including in an automatic and non-intrusive manner the key of an additional recipient, such as one intended for message recovery. By including in the user's key (e.g., an employee) a pointer to a message recovery agent's key (or the MRA key itself), the present invention readily solves the problem. Appended herewith as Appendix A are C/C++ source code listings providing further description of the present invention. A suitable development environment (e.g., compiler/linker) for compiling the code is available from a variety of compiler vendors, including Microsoft Corporation of Redmond, Wash. and Inprise Corporation (formally, Borland International, Inc.) of Scotts Valley, Calif. A set of comprehensive source listings for PGP 5.5.3i (Windows/Mac) is currently available on the Internet via FTP at ftp://ftp.no.pgpi.com/pub/pgp/5.5/win95nt/pgp553i-win95nt-src.zip (accessible from download page http://www.pgpi.com/download/#5.5i), the disclosure of which is hereby incorporated by reference. While the invention is described in some detail with specific reference to a single preferred embodiment and certain alternatives, there is no intent to limit the invention to that particular embodiment or those specific alternatives. Although examples have been presented using e-mail, for instance, those skilled in the art will appreciate that the methodology of the present invention may be applied to different modes of electronic communication, including wireless communication. Thus, the true scope of the present invention is not limited to any one of the foregoing exemplary embodiments but is instead defined by the appended claims.
APPENDIX A
/*.sub.
--------------------------------------------------------------------------
----------------
Copyright (C) 1997 Pretty Good Privacy, Inc.
All rights reserved.
.sub.
--------------------------------------------------------------------------
---------------- */
/* Notes:
The PGP client code does not directly encrypt to MRA's. All of the client
code modules call a "recipient" dialog function which presents a dialog
to the user containing two lists: available encryption keys and
encryption recipients. The user moves these keys from the key list to the
recipient list to choose the encryption recipients. If a key has one or
more associated MRA's, these are also moved to the recipients list and,
depending on the enforcement level of the software and embedded MRA, can
be moved back to the key list. Note that this operation can occur without
ever showing the dialog i. e. the recipients have been specified in an
email plugin via an email address, but the dialog function is always
called nonetheless. The client of the dialog function is returned a
PGPKeySet which contains the explicit and implict recipients and does not
make this distinction among them.
The following includes .cp and .h files for the Mac implementation of this
dialog. When a user drags one ore more keys from the key list to the
recipient list, the function SendSelectedToRecipients( ) is called which
marks the selected list items in our data structures and then calls
SendMarkedToRecipients( ). SendMarkedToRecipients( ) iterates over each
marked item and, for each marked key, calls
MarkADKeysForUserToRecipientMove( ) to also mark any associated MRA's. A
final pass "moves" all marked items to the recipient list. There is
similar logic for groups, which also appear in these lists.
*/
#include <LGACaption.h>
#include <LGACheckbox.h>
#include <LGAPushButton.h>
#include <PP_KeyCodes.h>
#include <UDrawingUtils.h>
#include <UGAColorRamp.
#include "pgpErrors.h"
#include "pgpGroupsUtil.h"
#include "pgpKeyServer.h"
#include "pgpMem.h"
#include <string.h>
#include "MacStrings.h"
#include "PGPRecipientGrafPort.h"
#include "PGPUILibDialogs.h"
#include "PGPUILibUtils.h"
#include "PGPSharedEncryptDecrypt.h"
#include "CUserIDTable.h"
#include "CPassPhraseEdit.h"
#include "CProgressBar.h"
#include "CFocusBorder.h"
#include "pgpDebug.h"
#include "CPrivateKeysPopup.h"
#include "pflPrefTypes.h"
#include "pgpClientPrefs.h"
#include "pgpEncode.h"
#include "pgpKeys.h"
#if PGP_BUSINESS_SECURITY
#include "pgpAdminPrefs.h"
#endif
enum
{
kMacBinaryPopupNoneMenuItem = 1,
kMacBinaryPopupSmartMenuItem,
kMacBinaryPopupYesMenuItem
};
const ResID kWarnSpecialADKDialogID = 4752;
const PaneIDT kUserIDScrollerPaneID = 3;
const PaneIDT kUserIDTablePaneID = 4;
const PaneIDT kFileOptionsBoxPaneID = 6;
const PaneIDT kTextOutputCheckboxPaneID = 7;
const PaneIDT kMacBinaryPopupPaneID = 8;
const PaneIDT kRecipientScrollerPaneID = 9;
const PaneIDT kRecipientTablePaneID = 10;
const PaneIDT kFileConvEncryptCheckboxPaneID = 11;
const PaneIDT kWipeOriginalCheckboxPaneID = 12;
const PaneIDT kTextOptionsBoxPaneID = 13;
const PaneIDT kTextConvEncryptCheckboxPaneID = 14;
const PaneIDT kInstructionsCaptionPaneID = 15;
const PaneIDT kUpdateFromServerButtonPaneID = 16;
const PaneIDT kUserIDFocusBorderPaneID = 17;
const PaneIDT kRecipientsFocusBorderPaneID = 18;
CPGPRecipientGrafPort::CPGPRecipientGrafPort(LStream *inStream)
: CPGPLibGrafPortView(inStream)
{
mMacBinaryPopup = NULL;
mTextOutputCheckbox = NULL;
mWipeOriginalCheckbox = NULL;
mConvEncryptCheckbox = NULL;
mUpdateFromServerButton = NULL;
mWindowIsMoveable = TRUE;
mWindowIsResizeable = TRUE;
mMinMaxSize.top = 300; // Minimum resize height
mMinMaxSize.bottom = 32000;// Maximum resize height
mMinMaxSize.left = 440; // Minimum resize width
mMinMaxSize.right = 640; // Maximum resize width
mUserIDListsEnabled = TRUE;
mHaveNewKeys = FALSE;
mHaveKeyServerSupport = CFM_AddressIsResolved_( PGPKeyServerInit );
mClientPrefsRef = kInvalidPGPPrefRef;
mAdminPrefsRef = kInvalidPGPPrefRef;
mContext = kInvalidPGPContextRef;
mEnforceRemoteADKClass = FALSE;
mGroupSet = kInvalidPGPGroupSetRef;
#if PGP_BUSINESS_SECURITY
mEnforceOutgoingADK = FALSE;
mCorporateKeyRef = kInvalidPGPKeyRef;
mOutgoingADKRef = kInvalidPGPKeyRef;
#endif
}
CPGPRecipientGrafPort::.about.CPGPRecipientGrafPort( )
{
/* Delete the backing store for the name list */
PGPRecipientTableItem::DisposeNameData( );
}
void
CPGPRecipientGrafPort::FinishCreateSelf( )
}
CFocusBorder *userIDBorder;
CPGPLibGrafPortView::FinishCreateSelf( );
mRecipientTable =
(CUserIDTable *) FindPaneByID( kRecipientTablePaneID );
mUserIDTable =
(CUserIDTable *) FindPaneByID( kUserIDTablePaneID );
mUserIDTable->InsertCols(1, 1, NULL, 0, TRUE);
mUserIDTable->AddListener(this);
mRecipientTable->InsertCols(1, 1, NULL, 0, TRUE);
mRecipientTable->AddListener (this);
mRecipientTable->SetAllowDeleteKeyToSend( TRUE );
mUpdateFromServerButton =
(LGAPushButton *) FindPaneByID ( kUpdateFromServerButtonPaneID );
if( mHaveKeyServerSupport )
{
mUpdateFromServerButton->AddListener ( this );
}
else
{
mUpdateFromServerButton->Hide ( );
}
userIDBorder = (CFocusBorder *)
FindPaneByID( kUserIDFocusBorderPaneID );
SwitchTarget ( userIDBorder );
AdjustButtons( );
}
PGPError
CPGPRecipientGrafPort::BuildRecipientList( )
{
PGPError err;
PGPKeyListRef keyList;
err = PGPOrderKeySet( mAllKeys, kPGPAnyOrdering, &keyList );
if( IsntPGPError( err ) )
{
PGPKeyIterRet keyIterator;
PGPKeyRef defaultKey = kInvalidPGPKeyRef;
if( IsPGPError( PGPGetDefaultPrivateKey( mAllKeys, &defaultKey ) )
)
{
defaultKey = (PGPKeyRet) kInvalidPGPKeyRef;
}
err = PGPNewKeyIter( keyList, &keyIterator );
it( IsntPGPError( err ) )
{
PGPKeyRet theKey;
err = PGPKeyIterNext ( keyIterator, &theKey );
while( IsntPGPError( err ) )
{
PGPBoolean keyCanEncrypt;
if( IsntPGPError( PGPKeyCanEncrypt( theKey,
&keyCanEncrypt ) ) && keyCanEncrypt
{
Boolean isDefault = theKey == defaultKey;
err = mUserIDTable->AddKey( theKey, isDefault, FALSE );
if( IsntPGPError( err ) )
{
// The user value of a key is set to a non-zero
// value when it has been added to a display list.
// This is convenient for checking for new keys added
// to the set via key server searches, etc.
err = PGPSetKeyUserVal( theKey,
(PGPUserValue) kKeyStateAddedFromClient );
}
}
if( IsPGPError( err ) )
break;
err = PGPKeyIterNext( keyIterator, &theKey };
}
if( err == kPGPError_EndOfIteration )
err = kPGPError_NoErr;
PGPFreeKeyIter( keyIterator );
}
PGPFreeKeyList( keyList );
}
/* now add all groups */
if ( IsntNull( mGroupSet ) )
{
PGPUInt32 numGroups;
err = PGPCountGroupsInSet( mGroupSet, &numGroups );
if ( IsntPGPError( err ) )
}
PGPUInt32 index;
for( index = 0; index < numGroups; ++index )
{
PGPGroupID id;
err = PGPGetIndGroupID( mGroupSet, index, &id );
if ( IsPGPError( err ) )
break;
err = mUserIDTable->AddGroup( mAllKeys,
mGroupSet, id );
if ( IsPGPError( err ) )
break;
}
}
}
return( err );
}
void
CPGPRecipientGrafPort::LockRecipient(UInt32 rowIndex)
{
PGPRecipientTableItem tableItem;
STableCell cell(rowIndex, 1);
mRecipientTable->GetCellData( cell, &tableItem );
tableItem.locked = TRUE;
mRecipientTable->SetCellData( cell, &tableItem );
}
#if PGP_BUSINESS_SECURITY // [
// Returns number of recipient keys not signed by the corporate key
PGPUInt32
CPGPRecipientGrafPort::GetNumKeysNotSignedByCorporateKey(
CUserIDTable *whichList,
PGPKeyRef corporateKeyRef,
Boolean markedOnly)
{
PGPUInt32 numUnsignedKeys = 0
PGPKeySetRef recipients;
PGPError err = kPGPError_NoErr;
err = whichList->CreateKeySet( mAllKeys, markedOnly, &recipients );
if ( IsntPGPError( err ) )
{
PGPKeyListRef keyList;
err = PGPOrderKeySet( recipients, kPGPAnyOrdering, &keyList );
if( IsntPGPError( err ) )
{
PGPKeyIterRef iter;
err = PGPNewKeyIter( keyList, &iter );
if( IsntPGPError( err ) )
{
PGPKeyRef key;
while( IsntPGPError( err = PGPKeyIterNext( iter, &key ) ) )
{
PGPUserIDRef userID;
PGPBoolean signedByCorporateKey = FALSE;
/* check all user ids for a corporate sig */
/* only one need be signed to qualify */
while( IsntPGPError( err =
PGPKeyIterNextUserID( iter, &userID)))
{
PGPSigRef sig;
while( IsntPGPError( err =
PGPKeyIterNextIDSig ( iter, &sig)))
{
PGPKeyRef certifierKey;
err = PGPGetSigCertifierKey( sig,
mAllKeys, &certifierKey);
if( IsntPGPError(err) )
{
if (certifierKey == corporateKeyRef)
{
signedByCorporateKey = TRUE;
break;
}
}
}
}
if ( ! signedByCorporateKey )
{
++numUnsignedKeys;
}
}
if ( err == kPGPError_EndOfIteration
err = kPGPError_NoErr;
PGPFreeKeyIter( iter );
}
PGPFreeKeyList ( keyList );
}
PGPFreeKeySet ( recipients );
}
pgpAssertNoErr( err );
return( numUnsignedKeys );
}
PGPError
CPGPRecipientGrafPort::MoveOutgoingAdditionalKey (void)
{
PGPError err = kPGPError_NoErr;
if( PGPKeyRefIsValid( mOutgoingADKRef ) )
{
UInt32 row;
if( mUserIDTable->HaveKey( mOutgoingADKRef, &row ) )
{
mUserIDTable->MarkOneRow( row );
SendMarkedToRecipients ( );
}
if( mRecipientTable->HaveKey( mOutgoingADKRef, &row ) )
{
if( mEnforceOutgoingADK )
{
LockRecipient( row );
}
}
else if( mEnforceOutgoingADK )
|
Same subclass Same class Consider this |
||||||||||
