linux/net/rxrpc/ar-key.c
<<
>>
Prefs
   1/* RxRPC key management
   2 *
   3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 *
  11 * RxRPC keys should have a description of describing their purpose:
  12 *      "afs@CAMBRIDGE.REDHAT.COM>
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/net.h>
  17#include <linux/skbuff.h>
  18#include <linux/key-type.h>
  19#include <linux/crypto.h>
  20#include <net/sock.h>
  21#include <net/af_rxrpc.h>
  22#include <keys/rxrpc-type.h>
  23#include <keys/user-type.h>
  24#include "ar-internal.h"
  25
  26static int rxrpc_instantiate(struct key *, const void *, size_t);
  27static int rxrpc_instantiate_s(struct key *, const void *, size_t);
  28static void rxrpc_destroy(struct key *);
  29static void rxrpc_destroy_s(struct key *);
  30static void rxrpc_describe(const struct key *, struct seq_file *);
  31
  32/*
  33 * rxrpc defined keys take an arbitrary string as the description and an
  34 * arbitrary blob of data as the payload
  35 */
  36struct key_type key_type_rxrpc = {
  37        .name           = "rxrpc",
  38        .instantiate    = rxrpc_instantiate,
  39        .match          = user_match,
  40        .destroy        = rxrpc_destroy,
  41        .describe       = rxrpc_describe,
  42};
  43EXPORT_SYMBOL(key_type_rxrpc);
  44
  45/*
  46 * rxrpc server defined keys take "<serviceId>:<securityIndex>" as the
  47 * description and an 8-byte decryption key as the payload
  48 */
  49struct key_type key_type_rxrpc_s = {
  50        .name           = "rxrpc_s",
  51        .instantiate    = rxrpc_instantiate_s,
  52        .match          = user_match,
  53        .destroy        = rxrpc_destroy_s,
  54        .describe       = rxrpc_describe,
  55};
  56
  57/*
  58 * instantiate an rxrpc defined key
  59 * data should be of the form:
  60 *      OFFSET  LEN     CONTENT
  61 *      0       4       key interface version number
  62 *      4       2       security index (type)
  63 *      6       2       ticket length
  64 *      8       4       key expiry time (time_t)
  65 *      12      4       kvno
  66 *      16      8       session key
  67 *      24      [len]   ticket
  68 *
  69 * if no data is provided, then a no-security key is made
  70 */
  71static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
  72{
  73        const struct rxkad_key *tsec;
  74        struct rxrpc_key_payload *upayload;
  75        size_t plen;
  76        u32 kver;
  77        int ret;
  78
  79        _enter("{%x},,%zu", key_serial(key), datalen);
  80
  81        /* handle a no-security key */
  82        if (!data && datalen == 0)
  83                return 0;
  84
  85        /* get the key interface version number */
  86        ret = -EINVAL;
  87        if (datalen <= 4 || !data)
  88                goto error;
  89        memcpy(&kver, data, sizeof(kver));
  90        data += sizeof(kver);
  91        datalen -= sizeof(kver);
  92
  93        _debug("KEY I/F VERSION: %u", kver);
  94
  95        ret = -EKEYREJECTED;
  96        if (kver != 1)
  97                goto error;
  98
  99        /* deal with a version 1 key */
 100        ret = -EINVAL;
 101        if (datalen < sizeof(*tsec))
 102                goto error;
 103
 104        tsec = data;
 105        if (datalen != sizeof(*tsec) + tsec->ticket_len)
 106                goto error;
 107
 108        _debug("SCIX: %u", tsec->security_index);
 109        _debug("TLEN: %u", tsec->ticket_len);
 110        _debug("EXPY: %x", tsec->expiry);
 111        _debug("KVNO: %u", tsec->kvno);
 112        _debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x",
 113               tsec->session_key[0], tsec->session_key[1],
 114               tsec->session_key[2], tsec->session_key[3],
 115               tsec->session_key[4], tsec->session_key[5],
 116               tsec->session_key[6], tsec->session_key[7]);
 117        if (tsec->ticket_len >= 8)
 118                _debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x",
 119                       tsec->ticket[0], tsec->ticket[1],
 120                       tsec->ticket[2], tsec->ticket[3],
 121                       tsec->ticket[4], tsec->ticket[5],
 122                       tsec->ticket[6], tsec->ticket[7]);
 123
 124        ret = -EPROTONOSUPPORT;
 125        if (tsec->security_index != 2)
 126                goto error;
 127
 128        key->type_data.x[0] = tsec->security_index;
 129
 130        plen = sizeof(*upayload) + tsec->ticket_len;
 131        ret = key_payload_reserve(key, plen);
 132        if (ret < 0)
 133                goto error;
 134
 135        ret = -ENOMEM;
 136        upayload = kmalloc(plen, GFP_KERNEL);
 137        if (!upayload)
 138                goto error;
 139
 140        /* attach the data */
 141        memcpy(&upayload->k, tsec, sizeof(*tsec));
 142        memcpy(&upayload->k.ticket, (void *)tsec + sizeof(*tsec),
 143               tsec->ticket_len);
 144        key->payload.data = upayload;
 145        key->expiry = tsec->expiry;
 146        ret = 0;
 147
 148error:
 149        return ret;
 150}
 151
 152/*
 153 * instantiate a server secret key
 154 * data should be a pointer to the 8-byte secret key
 155 */
 156static int rxrpc_instantiate_s(struct key *key, const void *data,
 157                               size_t datalen)
 158{
 159        struct crypto_blkcipher *ci;
 160
 161        _enter("{%x},,%zu", key_serial(key), datalen);
 162
 163        if (datalen != 8)
 164                return -EINVAL;
 165
 166        memcpy(&key->type_data, data, 8);
 167
 168        ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
 169        if (IS_ERR(ci)) {
 170                _leave(" = %ld", PTR_ERR(ci));
 171                return PTR_ERR(ci);
 172        }
 173
 174        if (crypto_blkcipher_setkey(ci, data, 8) < 0)
 175                BUG();
 176
 177        key->payload.data = ci;
 178        _leave(" = 0");
 179        return 0;
 180}
 181
 182/*
 183 * dispose of the data dangling from the corpse of a rxrpc key
 184 */
 185static void rxrpc_destroy(struct key *key)
 186{
 187        kfree(key->payload.data);
 188}
 189
 190/*
 191 * dispose of the data dangling from the corpse of a rxrpc key
 192 */
 193static void rxrpc_destroy_s(struct key *key)
 194{
 195        if (key->payload.data) {
 196                crypto_free_blkcipher(key->payload.data);
 197                key->payload.data = NULL;
 198        }
 199}
 200
 201/*
 202 * describe the rxrpc key
 203 */
 204static void rxrpc_describe(const struct key *key, struct seq_file *m)
 205{
 206        seq_puts(m, key->description);
 207}
 208
 209/*
 210 * grab the security key for a socket
 211 */
 212int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
 213{
 214        struct key *key;
 215        char *description;
 216
 217        _enter("");
 218
 219        if (optlen <= 0 || optlen > PAGE_SIZE - 1)
 220                return -EINVAL;
 221
 222        description = kmalloc(optlen + 1, GFP_KERNEL);
 223        if (!description)
 224                return -ENOMEM;
 225
 226        if (copy_from_user(description, optval, optlen)) {
 227                kfree(description);
 228                return -EFAULT;
 229        }
 230        description[optlen] = 0;
 231
 232        key = request_key(&key_type_rxrpc, description, NULL);
 233        if (IS_ERR(key)) {
 234                kfree(description);
 235                _leave(" = %ld", PTR_ERR(key));
 236                return PTR_ERR(key);
 237        }
 238
 239        rx->key = key;
 240        kfree(description);
 241        _leave(" = 0 [key %x]", key->serial);
 242        return 0;
 243}
 244
 245/*
 246 * grab the security keyring for a server socket
 247 */
 248int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
 249                         int optlen)
 250{
 251        struct key *key;
 252        char *description;
 253
 254        _enter("");
 255
 256        if (optlen <= 0 || optlen > PAGE_SIZE - 1)
 257                return -EINVAL;
 258
 259        description = kmalloc(optlen + 1, GFP_KERNEL);
 260        if (!description)
 261                return -ENOMEM;
 262
 263        if (copy_from_user(description, optval, optlen)) {
 264                kfree(description);
 265                return -EFAULT;
 266        }
 267        description[optlen] = 0;
 268
 269        key = request_key(&key_type_keyring, description, NULL);
 270        if (IS_ERR(key)) {
 271                kfree(description);
 272                _leave(" = %ld", PTR_ERR(key));
 273                return PTR_ERR(key);
 274        }
 275
 276        rx->securities = key;
 277        kfree(description);
 278        _leave(" = 0 [key %x]", key->serial);
 279        return 0;
 280}
 281
 282/*
 283 * generate a server data key
 284 */
 285int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
 286                              const void *session_key,
 287                              time_t expiry,
 288                              u32 kvno)
 289{
 290        const struct cred *cred = current_cred();
 291        struct key *key;
 292        int ret;
 293
 294        struct {
 295                u32 kver;
 296                struct rxkad_key tsec;
 297        } data;
 298
 299        _enter("");
 300
 301        key = key_alloc(&key_type_rxrpc, "x", 0, 0, cred, 0,
 302                        KEY_ALLOC_NOT_IN_QUOTA);
 303        if (IS_ERR(key)) {
 304                _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
 305                return -ENOMEM;
 306        }
 307
 308        _debug("key %d", key_serial(key));
 309
 310        data.kver = 1;
 311        data.tsec.security_index = 2;
 312        data.tsec.ticket_len = 0;
 313        data.tsec.expiry = expiry;
 314        data.tsec.kvno = 0;
 315
 316        memcpy(&data.tsec.session_key, session_key,
 317               sizeof(data.tsec.session_key));
 318
 319        ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL);
 320        if (ret < 0)
 321                goto error;
 322
 323        conn->key = key;
 324        _leave(" = 0 [%d]", key_serial(key));
 325        return 0;
 326
 327error:
 328        key_revoke(key);
 329        key_put(key);
 330        _leave(" = -ENOMEM [ins %d]", ret);
 331        return -ENOMEM;
 332}
 333EXPORT_SYMBOL(rxrpc_get_server_data_key);
 334
 335/**
 336 * rxrpc_get_null_key - Generate a null RxRPC key
 337 * @keyname: The name to give the key.
 338 *
 339 * Generate a null RxRPC key that can be used to indicate anonymous security is
 340 * required for a particular domain.
 341 */
 342struct key *rxrpc_get_null_key(const char *keyname)
 343{
 344        const struct cred *cred = current_cred();
 345        struct key *key;
 346        int ret;
 347
 348        key = key_alloc(&key_type_rxrpc, keyname, 0, 0, cred,
 349                        KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
 350        if (IS_ERR(key))
 351                return key;
 352
 353        ret = key_instantiate_and_link(key, NULL, 0, NULL, NULL);
 354        if (ret < 0) {
 355                key_revoke(key);
 356                key_put(key);
 357                return ERR_PTR(ret);
 358        }
 359
 360        return key;
 361}
 362EXPORT_SYMBOL(rxrpc_get_null_key);
 363