setkey.c revision 49e7ca4919cec3229f6fab9730bafc7cf24dab23
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Do the real work of the keyserver.
* Store secret keys. Compute common keys,
* and use them to decrypt and encrypt DES keys.
* Cache the common keys, so the expensive computation is avoided.
*/
#include <stdio.h>
#include <stdlib.h>
#include <mp.h>
#include <rpc/key_prot.h>
#include <rpc/des_crypt.h>
#include <rpcsvc/nis_dhext.h>
#include <string.h>
#include <thread.h>
#include <syslog.h>
#include "debug.h"
#include "keyserv_cache.h"
extern char ROOTKEY[];
extern mechanism_t **mechs;
extern char **cache_options;
extern int *cache_size;
extern int disk_caching;
static int hash_keys();
static int nodefaultkeys = 0;
#define DES "des"
#define DESALIAS "dh192-0"
#define DHMECHSTR "diffie_hellman"
#define CLASSIC_PK_DH(k, a) (((k) == 192) && ((a) == 0))
/*
* Exponential caching management
*/
struct cachekey_list {
struct cachekey_list *next;
};
#define KEY_HASH_SIZE 256
#ifdef DEBUG
int
{
return (0);
return (1);
}
int
real_debug(char *fmt, ...)
{
return (1);
}
#endif /* DEBUG */
struct cacheuid_list {
int refcnt;
struct cacheuid_list *next;
};
#define NUMHASHBUCKETS 256
#define HASH_UID(x) (x & 0xff)
struct mechdata {
};
struct psdata {
};
struct mechentry {
};
/*
* we don't need to worry about locking for the keylen + algtype
* sparse array because it is created once and for all during
* initialization when there are no threads. The mechentry field
* and everything underneath it needs protection and this is what
* the *_lock fields are for.
*/
struct algtypelist {
struct algtypelist *next;
};
struct keylenlist {
struct algtypelist *ap;
struct keylenlist *next;
};
#define KEYSERV_VERSION "1.0"
static struct mechtable {
char *version;
struct keylenlist *kp;
static struct keylenlist **
{
struct keylenlist **kpp;
return (kpp);
}
static void
{
struct keylenlist *kp;
return;
}
} else {
/*EMPTY*/
/* do nothing; only happens for multiple algtypes */
("appendkeylist called for non tail element"));
}
}
static struct algtypelist **
{
struct algtypelist **app;
return (app);
}
static void
{
struct algtypelist *ap;
return;
}
} else {
/*EMPTY*/
/* don't mind duplicate (keylen,algtype) paris for now. */
("appendalgtype called for non tail element"));
}
}
static struct mechentry *
{
struct keylenlist **kpp;
struct algtypelist **app;
return (0);
}
return (0);
}
}
static keybuf3 *
getkeybuf3(int k)
{
return (NULL);
}
buf->keybuf3_len = k;
/* XXX special case k==0 */
if (k == 0) {
} else {
return (NULL);
}
}
return (buf);
}
static void
{
return;
if (kp->keybuf3_val) {
/* XXX kp->keybuf3_len != 0? */
}
}
static keybuf3 *
{
return (NULL);
}
return (NULL);
}
return (dst);
}
static keybuf3 *
{
return (NULL);
}
return (dst);
}
static int
{
return (0);
}
return (0);
}
}
static int
{
return (0);
}
return (1);
}
static deskeyarray *
getdeskeyarray(int k)
{
return (NULL);
}
buf->deskeyarray_len = k;
/* XXX special case k==0 */
if (k == 0) {
} else {
return (NULL);
}
}
return (buf);
}
static deskeyarray *
{
return (NULL);
}
return (NULL);
}
return (dst);
}
static int
{
return (0);
}
return (1);
}
int
{
return (0);
}
return (1);
}
static int
{
}
static struct cacheuid_list **
{
struct cacheuid_list **cpp;
}
return (cpp);
}
static int
{
return (0);
}
return (0);
}
("appendsecretkey3 : calloc failed"));
return (0);
}
}
("appendsecretkey3 : malloc failed"));
return (0);
}
} else {
}
return (0);
}
return (0);
}
return (1);
}
/*
* Store the vers 3 secretkey for this uid
*/
static int
{
return (0);
}
return (0);
}
}
/*
* Set the vers 3 secretkey key for this uid
*/
{
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
/*
* Set the secretkey key for this uid
*/
{
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
int
{
struct keylenlist *kp;
struct algtypelist *ap;
return (0);
}
("storeotherrootkeys calling getsecretkey_g"));
if (!getsecretkey_g(netname,
passwd)) {
("Can't find %s's secret key", netname));
return (0);
}
("Password does not decrypt secret key for %s",
netname));
return (0);
}
}
return (0);
}
}
}
}
return (1);
}
/*
* prohibit the nobody key on this machine k (the -d flag)
*/
int
{
nodefaultkeys = 1;
return (0);
}
static void
{
return;
}
}
{
struct keylenlist *kp;
struct algtypelist *ap;
continue;
}
continue;
}
freedisklist(*cpp);
}
}
/* XXX clear stuff out of the common key cache as well? */
/* XXX return success only if something was removed? */
return (KEY_SUCCESS);
}
/*
* Set the modulus for all our Diffie-Hellman operations
*/
int
char *modx;
{
return (0);
}
/*
* Encrypt the key using the public key associated with remote_name and the
* secret key associated with uid.
*/
char *remote_name;
{
}
/*
* Encrypt the key using the public key associated with remote_name and the
* secret key associated with uid using vers 3
*/
)
{
}
/*
* Decrypt the key using the public key associated with remote_name and the
* secret key associated with uid.
*/
char *remote_name;
{
}
/*
* Decrypt the key using the public key associated with remote_name and the
* secret key associated with uid using vers 3
*/
)
{
}
/*
* Key storage management
*/
#define KEY_ONLY 0
#define KEY_NAME 1
struct secretkey_netname_list {
struct secretkey_netname_list *next;
};
#define HASH_UID(x) (x & 0xff)
/*
* Store the keys and netname for this uid
*/
static int
{
struct secretkey_netname_list *new;
struct secretkey_netname_list **l;
(void) rw_wrlock(&g_secretkey_netname_lock);
l = &(*l)->next) {
}
if (*l == NULL) {
/* LINTED pointer alignment */
(void) rw_unlock(&g_secretkey_netname_lock);
return (0);
}
*l = new;
} else {
new = *l;
}
if (netstore->st_netname)
else
(void) rw_unlock(&g_secretkey_netname_lock);
return (1);
}
static int
{
return (0);
}
return (0);
}
}
return (0);
}
} else {
}
return (0);
}
return (0);
}
if (net->st_netname) {
} else {
}
return (1);
}
{
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
/*
* Store the keys and netname for this uid vers 3
*/
static int
{
return (0);
}
return (0);
}
"keyserv: could not set root's key and netname.\n");
return (0);
}
}
}
{
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
int
{
return (0);
}
/* the +1 is mandated by getpublickey_g() */
return (0);
}
/*
* getpublickey_g(netname, keylen, algtype,
* public->keybuf3_val, public->keybuf3_len);
* cannot be called since rpc.nisd is not up yet
* so we continue to return a zero filled public key
* as in the earlier version
*/
return (store_netname3(0, &tmp));
}
/*
* Fetch the keys and netname for this uid
*/
static int
struct key_netstarg *key_netst;
{
struct secretkey_netname_list *l;
(void) rw_rdlock(&g_secretkey_netname_lock);
if (l->keynetdata.st_netname)
l->keynetdata.st_netname);
else
(void) rw_unlock(&g_secretkey_netname_lock);
return (1);
}
}
(void) rw_unlock(&g_secretkey_netname_lock);
return (0);
}
static void
{
/*
* XXX
* if we are going to do this along the lines of vn_rele,
* more stuff needs to be done here and the access to refcnt
* needs to be mutex locked. Keep it simple for now.
*/
}
static void
{
struct cacheuid_list *cp;
return;
}
/*LINTED assignment operator "=" found where "==" was expected*/
}
}
static struct cacheuid_list *
{
return (0);
}
return (0);
}
return (cp);
}
/*
* Fetch any available cache for this uid (vers 3)
*/
static struct cacheuid_list *
{
struct keylenlist *kp;
struct algtypelist *ap;
continue;
}
continue;
}
return (cp);
}
}
return (NULL);
}
static struct cacheuid_list *
{
struct cacheuid_list *cp;
return (NULL);
}
return (NULL);
}
return (cp);
}
/*
* Fetch the keys and netname for this uid vers 3
*/
static int
{
struct cacheuid_list *cp;
return (0);
}
} else {
}
return (0);
}
return (0);
}
return (0);
}
} else {
}
remove_ref(cp);
return (1);
}
{
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
{
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
/*
* Try to find the common key in the cache
*/
static int
char *pub;
char *sec;
int hash;
{
register struct cachekey_list **l;
l = &(*l)->next)
;
if ((*l) == NULL)
return (0);
return (1);
}
/*
* cache result of expensive multiple precision exponential operation
*/
static int
char *pub;
char *sec;
int hash;
{
struct cachekey_list *new;
return (0);
}
return (1);
}
/*
* Choose middle 64 bits of the common key to use as our des key, possibly
* overwriting the lower order bits by setting parity.
*/
static int
{
MINT *a;
short r;
int i;
char *k;
a = mp_itom(0);
}
k = deskey->c;
for (i = 0; i < 8; i++) {
*k++ = r;
}
mp_mfree(a);
des_setparity((char *)deskey);
return (0);
}
static bool_t
char *buf;
{
struct secretkey_netname_list *l;
(void) rw_rdlock(&g_secretkey_netname_lock);
sizeof (keybuf));
(void) rw_unlock(&g_secretkey_netname_lock);
return (TRUE);
}
}
(void) rw_unlock(&g_secretkey_netname_lock);
return (FALSE);
}
static keybuf3 *
{
struct cacheuid_list *cp;
return (NULL);
}
}
/*
* Do the work of pk_encrypt && pk_decrypt
*/
static keystatus
char *remote_name;
int mode;
{
char xsecret[1024];
char xpublic[1024];
int err;
char zero[8];
int hash;
if (nodefaultkeys)
return (KEY_NOSECRET);
return (KEY_NOSECRET);
}
}
if (remote_key) {
} else {
return (KEY_UNKNOWN);
}
}
(void) rw_rdlock(&g_cachedkeys_lock);
(void) rw_unlock(&g_cachedkeys_lock);
(void) rw_wrlock(&g_cachedkeys_lock);
/* Sanity Check on public and private keys */
(void) rw_unlock(&g_cachedkeys_lock);
return (KEY_SYSTEMERR);
}
}
}
(void) rw_unlock(&g_cachedkeys_lock);
if (DES_FAILED(err)) {
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
static int
{
int i;
int hash = 0;
char *pub = p->keybuf3_val;
char *sec = s->keybuf3_val;
p->keybuf3_len, pub));
s->keybuf3_len, sec));
}
return (hash & 0xff);
}
static struct cachekey3_list **
{
struct cachekey3_list **cpp;
}
return (cpp);
}
static struct cachekey3_list *
int desarylen,
)
{
struct cacheuid_list *cu;
int i;
int cached = 0;
return (0);
}
NULL) {
return (0);
}
}
if (disk_caching &&
("getdeskey3 calling cache_retrieve"));
cached = 1;
} else {
("getdeskey3 calling cache_remove"));
}
}
}
if (cached) {
} else {
if ((cp = (struct cachekey3_list *)
("getdeskey3 : malloc failed"));
"file %s line %d: malloc failed",
return (0);
}
return (0);
}
return (0);
}
return (0);
}
("getdeskey3 calling __gen_common_dhkeys_g"));
return (0);
}
for (i = 0; i < desarylen; i++) {
("getdeskey3 gendh key : (%x,%x)",
}
("getdeskey3 calling cache_insert"));
}
}
} else {
}
return (cp);
}
{
char zero[8];
struct cachekey3_list *cp;
if (nodefaultkeys)
return (KEY_NOSECRET);
return (KEY_SYSTEMERR);
}
("pk_get_conv_key3 calling getsecretkey_g"));
if (!getsecretkey_g("nobody",
("pk_get_conv_key3 calling getsecretkey_g failed"));
return (KEY_NOSECRET);
}
("pk_get_conv_key3 calling getsecretkey_g succeeded"));
}
return (KEY_SYSTEMERR);
}
return (KEY_SUCCESS);
}
/*
* Do the work of pk_encrypt3 && pk_decrypt3
*/
static keystatus
int mode
)
{
char zero[8];
struct cachekey3_list *cp;
int err;
int xsecret_alloc = 0;
char ivec[8];
if (nodefaultkeys)
return (KEY_NOSECRET);
return (KEY_SYSTEMERR);
}
xsecret_alloc = 1;
if (!getsecretkey_g("nobody",
("pk_crypt3 calling getsecretkey_g failed"));
return (KEY_NOSECRET);
}
/* XXX optimize to cache nobody's secret key? */
("pk_crypt3 calling getsecretkey_g succeeded"));
}
return (KEY_SYSTEMERR);
}
} else {
return (KEY_SYSTEMERR);
}
("pk_crypt3 calling getpublickey_g nobody"));
("pk_crypt3 calling getpublickey_g nobody failed"));
return (KEY_UNKNOWN);
}
}
("pk_crypt3 calling getpublickey_g succeeded"));
}
return (KEY_SYSTEMERR);
}
/*EMPTY*/
("pk_crypt3 WARNING received 192-bit key"));
} else {
("pk_crypt3 calling __cbc_triple_crypt"));
(char *)key->deskeyarray_val,
if (DES_FAILED(err)) {
("pk_crypt3 calling ecb_crypt/__cbc_triple_crypt failed"));
return (KEY_SYSTEMERR);
}
("pk_crypt3 calling __cbc_triple_crypt succeeded"));
}
return (KEY_SUCCESS);
}
{
char xsecret[1024];
char xpublic[1024];
char zero[8];
int hash;
if (nodefaultkeys)
return (KEY_NOSECRET);
xsecret[0] == 0)
return (KEY_NOSECRET);
}
(void) rw_rdlock(&g_cachedkeys_lock);
(void) rw_unlock(&g_cachedkeys_lock);
(void) rw_wrlock(&g_cachedkeys_lock);
hash)) {
/* Sanity Check on public and private keys */
(void) rw_unlock(&g_cachedkeys_lock);
return (KEY_SYSTEMERR);
}
}
}
(void) rw_unlock(&g_cachedkeys_lock);
return (KEY_SUCCESS);
}
/*
* Remove common keys from the cache.
*/
static int
char *sec;
{
struct cachekey_list *found;
register struct cachekey_list **l;
int i;
(void) rw_wrlock(&g_cachedkeys_lock);
for (i = 0; i < KEY_HASH_SIZE; i++) {
for (l = &g_cachedkeys[i]; (*l) != NULL; ) {
found = *l;
*l = (*l)->next;
sizeof (struct cachekey_list));
} else {
l = &(*l)->next;
}
}
}
(void) rw_unlock(&g_cachedkeys_lock);
return (1);
}
/*
* Store the secretkey for this uid
*/
int
{
struct secretkey_netname_list *new;
struct secretkey_netname_list **l;
(void) rw_wrlock(&g_secretkey_netname_lock);
l = &(*l)->next) {
}
if (*l == NULL) {
if (key[0] == '\0') {
(void) rw_unlock(&g_secretkey_netname_lock);
return (0);
}
(void) rw_unlock(&g_secretkey_netname_lock);
return (0);
}
*l = new;
} else {
new = *l;
if (key[0] == '\0')
}
(void) rw_unlock(&g_secretkey_netname_lock);
return (1);
}
static int
int val;
{
return ("0123456789abcdef"[val]);
}
int
unsigned char *bin;
unsigned char *hex;
int size;
{
int i;
for (i = 0; i < size; i++) {
}
return (0);
}
static int
char dig;
{
return (dig - '0');
} else {
return (-1);
}
}
int
unsigned char *hex;
unsigned char *bin;
int size;
{
int i;
for (i = 0; i < size; i++) {
}
return (0);
}
static int
char *pub;
char *sec;
{
int i;
int hash = 0;
}
return (hash & 0xff);
}
/*
* problem: keyserv loads keys from /etc/.rootkey based on nisauthconf(1M)
* which is too nis+-centric (see secure_rpc(3N)).
*
* So we want to make sure there is always a AUTH_DES compat entry
* in the "list" of nis+ mechs so that the 192bit key always gets loaded so
* non-nis+ services that use AUTH_DES (e.g. nfs) won't get hosed. The real
* hacky part of it is we muck with the array returned from
* __nis_get_mechanisms which we really don't have any business
* way would be to change the __nis_get_mechanisms interface or add another
* one similiar to it that forces the "des" compat entry into the list.
*
* Return ptr to mechs array on success, else NULL on memory errs.
*/
mechanism_t **
{
int i = 0;
if (mechs) {
/* got some valid mechs and possibly the AUTH_DES compat one */
for (i = 0; mechs[i]; i++) {
if (AUTH_DES_COMPAT_CHK(mechs[i]))
return (mechs);
}
/* i == number of ptrs not counting terminating NULL */
}
/* AUTH_DES compat entry not found, let's add it */
if (mechs)
return (NULL);
}
/* mechs == NULL and i == 0 is valid "no mechs configed" case */
if (mechsbak)
return (NULL);
}
return (mechs);
}
int
{
int nmechs, oldmechseen;
char **cpp;
if (!(mechs = getmechwrap()))
return (-1);
/*
* find how many mechanisms were specified and also
*/
nmechs = 0;
struct keylenlist **kpp;
struct algtypelist **app;
nmechs++;
continue;
}
}
/*
* set of mechs for getsubopt()
*/
sizeof (*cache_options));
if (cache_options == NULL) {
return (-1);
}
/*
* cache sizes
*/
if (cache_size == NULL) {
return (-1);
}
oldmechseen = 0;
cpp = cache_options;
/*
* usual case: a DH-style mechanism type, with an alias
*/
/*
* Is this trad 192-DH? already added?
*/
if (oldmechseen) {
continue;
}
oldmechseen++;
}
continue;
}
/*
* HACK: we recognise a special alias for traditional
* 192-bit DH, unless the latter has already been mentioned
* in it's full form
*/
oldmechseen++;
continue;
}
/*
* Ignore anything else
*/
}
/* Terminate the options list */
return (0);
}