]> git.saurik.com Git - apple/network_cmds.git/blobdiff - racoon.tproj/oakley.c
network_cmds-245.19.tar.gz
[apple/network_cmds.git] / racoon.tproj / oakley.c
index 5caa962f06db1d67bbe736748159ea79e1bf3f56..3c7cb819baef0c38bdd54295b2cb08c8d6cd6a5e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $KAME: oakley.c,v 1.111 2001/12/20 23:33:22 sakane Exp $        */
+/*     $KAME: oakley.c,v 1.115 2003/01/10 08:38:23 sakane Exp $        */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -33,6 +33,7 @@
 #include <sys/param.h>
 #include <sys/socket.h>        /* XXX for subjectaltname */
 #include <netinet/in.h>        /* XXX for subjectaltname */
+#include <arpa/inet.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include "sainfo.h"
 #include "proposal.h"
 #include "crypto_openssl.h"
+#include "crypto_cssm.h"
+#include "open_dir.h"
 #include "dnssec.h"
 #include "sockmisc.h"
 #include "strnames.h"
 #include "gcmalloc.h"
+#ifndef HAVE_ARC4RANDOM
+#include "arc4random.h"
+#endif
 
 #ifdef HAVE_GSSAPI
 #include "gssapi.h"
@@ -89,6 +95,7 @@ do {                                                                           \
        memset(&a, 0, sizeof(struct dhgroup));                                 \
        a.type = (t);                                                          \
        a.prime = vdup(&buf);                                                  \
+       racoon_free(buf.v);                                                                                                                             \
        a.gen1 = 2;                                                            \
        a.gen2 = 0;                                                            \
 } while(0);
@@ -105,7 +112,7 @@ struct dhgroup dh_modp8192;
 static int oakley_compute_keymat_x __P((struct ph2handle *, int, int));
 #ifdef HAVE_SIGNING_C
 static int get_cert_fromlocal __P((struct ph1handle *, int));
-static int oakley_check_certid __P((struct ph1handle *iph1));
+static int oakley_check_certid(u_int8_t idtype, int idlen, void* id, cert_t* cert_p);
 static int check_typeofcertname __P((int, int));
 static cert_t *save_certbuf __P((struct isakmp_gen *));
 #endif
@@ -199,7 +206,7 @@ oakley_dh_compute(dh, pub, priv, pub_p, gxy)
 
 #ifdef ENABLE_STATS
        gettimeofday(&end, NULL);
-       syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __FUNCTION__,
+       syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__,
                s_attr_isakmp_group(dh->type), dh->prime->l << 3,
                timedelta(&start, &end));
 #endif
@@ -246,7 +253,7 @@ oakley_dh_generate(dh, pub, priv)
 
 #ifdef ENABLE_STATS
        gettimeofday(&end, NULL);
-       syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __FUNCTION__,
+       syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __func__,
                s_attr_isakmp_group(dh->type), dh->prime->l << 3,
                timedelta(&start, &end));
 #endif
@@ -356,7 +363,7 @@ oakley_hash(buf, iph1)
        res = alg_oakley_hashdef_one(type, buf);
        if (res == NULL) {
                plog(LLV_ERROR, LOCATION, NULL,
-                       "invalid hash algoriym %d.\n", type);
+                       "invalid hash algorithm %d.\n", type);
                return NULL;
        }
 
@@ -1265,18 +1272,34 @@ oakley_validate_auth(iph1)
                        return ISAKMP_INTERNAL_ERROR;
                }
 
-               /* compare ID payload and certificate name */
-               if (iph1->rmconf->verify_cert &&
-                   (error = oakley_check_certid(iph1)) != 0)
-                       return error;
+               /* check cert ID */
+               if (iph1->rmconf->verify_cert) {
+               
+                       struct ipsecdoi_id_b *id_b;
+                       int idlen;
+                       
+                       if (iph1->id_p == NULL || iph1->cert_p == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL, "no ID or CERT found.\n");
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       }
+                       
+                       id_b = (struct ipsecdoi_id_b *)iph1->id_p->v;
+                       idlen = iph1->id_p->l - sizeof(*id_b);
+                       
+                   if ((error = oakley_check_certid(id_b->type, idlen, id_b + 1, iph1->cert_p)) != 0)
+                               return error;
+               }
 
                /* verify certificate */
                if (iph1->rmconf->verify_cert
                 && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) {
                        switch (iph1->rmconf->certtype) {
                        case ISAKMP_CERT_X509SIGN:
-                               error = eay_check_x509cert(&iph1->cert_p->cert,
-                                       lcconf->pathinfo[LC_PATHTYPE_CERT]);
+                               if (iph1->rmconf->cert_verification == VERIFICATION_MODULE_SEC_FRAMEWORK)
+                                       error = crypto_cssm_check_x509cert(&iph1->cert_p->cert);
+                               else
+                                       error = eay_check_x509cert(&iph1->cert_p->cert,
+                                               lcconf->pathinfo[LC_PATHTYPE_CERT], 0);
                                break;
                        default:
                                plog(LLV_ERROR, LOCATION, NULL,
@@ -1286,12 +1309,69 @@ oakley_validate_auth(iph1)
                        }
                        if (error != 0) {
                                plog(LLV_ERROR, LOCATION, NULL,
-                                       "Invalid authority of the CERT.\n");
+                                       "the peer's certificate is not verified.\n");
                                return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY;
                        }
+                       
+               }
+               
+               /* check configured peers identifier against cert IDs                           */
+               /* allows checking of specified ID against multiple ids in the cert */
+               /* such as multiple domain names                                                                        */
+               if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER) {
+                       u_int8_t doi_type = 255;
+                       void *peers_id = NULL;
+                       int     peers_id_len = 0;
+                       
+                       if (iph1->rmconf->idvtype_p == IDTYPE_ADDRESS) {
+                               switch (((struct sockaddr *)(iph1->rmconf->idv_p->v))->sa_family) {                                                     
+                                       case AF_INET:
+                                               doi_type = IPSECDOI_ID_IPV4_ADDR;
+                                               peers_id_len = sizeof(struct in_addr);
+                                               peers_id = &(((struct sockaddr_in *)(iph1->rmconf->idv_p->v))->sin_addr.s_addr);
+                                               break;
+#ifdef INET6
+                                       case AF_INET6:
+                                               doi_type = IPSECDOI_ID_IPV6_ADDR;
+                                               peers_id_len = sizeof(struct in6_addr);
+                                               peers_id = &(((struct sockaddr_in6 *)(iph1->rmconf->idv_p->v))->sin6_addr.s6_addr);
+                                               break;
+#endif
+                                       default:
+                                               plog(LLV_ERROR, LOCATION, NULL,
+                                                       "unknown address type for peers identifier.\n");
+                                               return ISAKMP_NTYPE_AUTHENTICATION_FAILED;
+                                               break;
+                               }
+                               
+                       } else {
+                               doi_type = idtype2doi(iph1->rmconf->idvtype_p);
+                               peers_id = iph1->rmconf->idv_p->v;
+                               peers_id_len = iph1->rmconf->idv_p->l;
+                       }
+
+                       if ((error = oakley_check_certid(doi_type, peers_id_len, 
+                                       peers_id, iph1->cert_p)) != 0)
+                               return error;                   
                }
 
+               if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_OPEN_DIR) {
+                       
+                       vchar_t *user_id = NULL;
+                       
+                       user_id = eay_get_x509_common_name(&iph1->cert_p->cert);
+                       
+                       // the following functions will check if user_id == 0
+                       if (open_dir_authorize_id(user_id, iph1->rmconf->open_dir_auth_group) == 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                               "the peer is not authorized for access.\n");
+                               return ISAKMP_NTYPE_AUTHENTICATION_FAILED;
+                       }
+                       vfree(user_id);
+               }
+               
                plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n");
+               
 
                /* compute hash */
                switch (iph1->etype) {
@@ -1395,7 +1475,7 @@ oakley_validate_auth(iph1)
        }
 #ifdef ENABLE_STATS
        gettimeofday(&end, NULL);
-       syslog(LOG_NOTICE, "%s(%s): %8.6f", __FUNCTION__,
+       syslog(LOG_NOTICE, "%s(%s): %8.6f", __func__,
                s_oakley_attr_method(iph1->approval->authmethod),
                timedelta(&start, &end));
 #endif
@@ -1441,33 +1521,36 @@ get_cert_fromlocal(iph1, my)
                certfile = iph1->rmconf->peerscertfile;
                certpl = &iph1->cert_p;
        }
-       if (!certfile) {
+       if (!certfile && iph1->rmconf->identity_in_keychain == 0) {
                plog(LLV_ERROR, LOCATION, NULL, "no CERT defined.\n");
                return 0;
        }
 
        switch (iph1->rmconf->certtype) {
-       case ISAKMP_CERT_X509SIGN:
-       case ISAKMP_CERT_DNS:
-               /* make public file name */
-               getpathname(path, sizeof(path), LC_PATHTYPE_CERT, certfile);
-               cert = eay_get_x509cert(path);
-               if (cert) {
-                       char *p = NULL;
-                       p = eay_get_x509text(cert);
-                       plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n");
-                       racoon_free(p);
-               };
-               break;
-
-       default:
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "not supported certtype %d\n",
-                       iph1->rmconf->certtype);
-               goto end;
+               case ISAKMP_CERT_X509SIGN:
+                       if (iph1->rmconf->identity_in_keychain) {
+                               cert = crypto_cssm_get_x509cert(iph1->rmconf->keychainCertRef);
+                               break;
+                       } // else fall thru
+               case ISAKMP_CERT_DNS:
+                       /* make public file name */
+                       getpathname(path, sizeof(path), LC_PATHTYPE_CERT, certfile);
+                       cert = eay_get_x509cert(path);
+                       break;
+       
+               default:
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "not supported certtype %d\n",
+                               iph1->rmconf->certtype);
+                       goto end;
        }
-
-       if (!cert) {
+       
+       if (cert) {
+               char *p = NULL;
+               p = eay_get_x509text(cert);
+               plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n");
+               racoon_free(p);
+       } else {
                plog(LLV_ERROR, LOCATION, NULL,
                        "failed to get %s CERT.\n",
                        my ? "my" : "peers");
@@ -1517,6 +1600,11 @@ oakley_getsign(iph1)
 
        switch (iph1->rmconf->certtype) {
        case ISAKMP_CERT_X509SIGN:
+               // cert in keychain - use cssm to sign
+               if (iph1->rmconf->identity_in_keychain) {
+                       iph1->sig = crypto_cssm_getsign(iph1->rmconf->keychainCertRef, iph1->hash);
+                       break;
+               } // else fall thru
        case ISAKMP_CERT_DNS:
                if (iph1->rmconf->myprivfile == NULL) {
                        plog(LLV_ERROR, LOCATION, NULL, "no cert defined.\n");
@@ -1538,6 +1626,7 @@ oakley_getsign(iph1)
 
                iph1->sig = eay_get_x509sign(iph1->hash,
                                        privkey, &iph1->cert->cert);
+                                               
                break;
        default:
                goto end;
@@ -1564,26 +1653,16 @@ end:
  * compare certificate name and ID value.
  */
 static int
-oakley_check_certid(iph1)
-       struct ph1handle *iph1;
+oakley_check_certid(u_int8_t idtype, int idlen, void* id, cert_t* cert_p)
 {
-       struct ipsecdoi_id_b *id_b;
        vchar_t *name = NULL;
        char *altname = NULL;
-       int idlen, type;
+       int type, len;
        int error;
 
-       if (iph1->id_p == NULL || iph1->cert_p == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n");
-               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
-       }
-
-       id_b = (struct ipsecdoi_id_b *)iph1->id_p->v;
-       idlen = iph1->id_p->l - sizeof(*id_b);
-
-       switch (id_b->type) {
+       switch (idtype) {
        case IPSECDOI_ID_DER_ASN1_DN:
-               name = eay_get_x509asn1subjectname(&iph1->cert_p->cert);
+               name = eay_get_x509asn1subjectname(&cert_p->cert);
                if (!name) {
                        plog(LLV_ERROR, LOCATION, NULL,
                                "failed to get subjectName\n");
@@ -1595,7 +1674,7 @@ oakley_check_certid(iph1)
                        vfree(name);
                        return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
                }
-               error = memcmp(id_b + 1, name->v, idlen);
+               error = memcmp(id, name->v, idlen);
                vfree(name);
                if (error != 0) {
                        plog(LLV_ERROR, LOCATION, NULL,
@@ -1603,21 +1682,28 @@ oakley_check_certid(iph1)
                        return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
                }
                return 0;
-       case IPSECDOI_ID_IPV4_ADDR:
+       case IPSECDOI_ID_IPV4_ADDR:                     
        case IPSECDOI_ID_IPV6_ADDR:
        {
-               /*
-                * converting to binary from string because openssl return
-                * a string even if object is a binary.
-                * XXX fix it !  access by ASN.1 directly without.
-                */
-               struct addrinfo hints, *res;
-               caddr_t a = NULL;
+
+               /* 
+                * Openssl returns the IPAddress as an ASN1 octet string (binary format)
+                * followed by a trailing NULL.  5 bytes for IPv4 and 17 bytes for IPv6
+                */     
+               #define SUBJ_ALT_NAME_IPV4_ADDRESS_LEN  5
+               #define SUBJ_ALT_NAME_IPV6_ADDRESS_LEN  17
+               
                int pos;
+               
+               if (idtype == IPSECDOI_ID_IPV4_ADDR && idlen != sizeof(struct in_addr)
+                       || idtype == IPSECDOI_ID_IPV6_ADDR && idlen != sizeof(struct in6_addr)) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid address length passed.\n");
+                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+               }
 
                for (pos = 1; ; pos++) {
-                       if (eay_get_x509subjectaltname(&iph1->cert_p->cert,
-                                       &altname, &type, pos) !=0) {
+                       if (eay_get_x509subjectaltname(&cert_p->cert, &altname, &type, pos, &len) !=0) {
                                plog(LLV_ERROR, LOCATION, NULL,
                                        "failed to get subjectAltName\n");
                                return ISAKMP_NTYPE_INVALID_CERTIFICATE;
@@ -1625,54 +1711,53 @@ oakley_check_certid(iph1)
 
                        /* it's the end condition of the loop. */
                        if (!altname) {
-                               plog(LLV_ERROR, LOCATION, NULL,
-                                       "no proper subjectAltName.\n");
-                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
                        }
 
-                       if (check_typeofcertname(id_b->type, type) == 0)
-                               break;
-
-                       /* next name */
-                       racoon_free(altname);
-                       altname = NULL;
-               }
-               memset(&hints, 0, sizeof(hints));
-               hints.ai_family = PF_UNSPEC;
-               hints.ai_socktype = SOCK_RAW;
-               hints.ai_flags = AI_NUMERICHOST;
-               error = getaddrinfo(altname, NULL, &hints, &res);
-               if (error != 0) {
-                       plog(LLV_ERROR, LOCATION, NULL,
-                               "no proper subjectAltName.\n");
-                       racoon_free(altname);
-                       return ISAKMP_NTYPE_INVALID_CERTIFICATE;
-               }
-               switch (res->ai_family) {
-               case AF_INET:
-                       a = (caddr_t)&((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr;
-                       break;
+                       if (check_typeofcertname(idtype, type) != 0) {
+                               /* wrong type - skip this one */
+                               racoon_free(altname);
+                               altname = NULL;
+                               continue;
+                       }
+               
+                       if (len == SUBJ_ALT_NAME_IPV4_ADDRESS_LEN) { /* IPv4 */
+                               if (idtype != IPSECDOI_ID_IPV4_ADDR) {
+                                       /* wrong IP address type - skip this one */                             
+                                       racoon_free(altname);
+                                       altname = NULL;
+                                       continue;
+                               }
+                       }
 #ifdef INET6
-               case AF_INET6:
-                       a = (caddr_t)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr;
-                       break;
+                       else if (len == SUBJ_ALT_NAME_IPV6_ADDRESS_LEN) { /* IPv6 */
+                               if (idtype != IPSECDOI_ID_IPV6_ADDR) {
+                                       /* wrong IP address type - skip this one */                             
+                                       racoon_free(altname);
+                                       altname = NULL;
+                                       continue;
+                               }
+                       }
 #endif
-               default:
-                       plog(LLV_ERROR, LOCATION, NULL,
-                               "family not supported: %d.\n", res->ai_family);
+                       else {
+                               /* invalid IP address length in certificate - bad or bogus certificate */
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "invalid IP address in certificate.\n");
+                               racoon_free(altname);
+                               altname = NULL;
+                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                       }
+                       
+                       /* compare the addresses */             
+                       error = memcmp(id, altname, idlen);
                        racoon_free(altname);
-                       freeaddrinfo(res);
-                       return ISAKMP_NTYPE_INVALID_CERTIFICATE;
-               }
-               error = memcmp(id_b + 1, a, idlen);
-               freeaddrinfo(res);
-               vfree(name);
-               if (error != 0) {
-                       plog(LLV_ERROR, LOCATION, NULL,
-                               "ID mismatched with subjectAltName.\n");
-                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       if (error != 0) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                                       "ID mismatched with subjectAltName.\n");
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       }
+                       return 0;
                }
-               return 0;
        }
        case IPSECDOI_ID_FQDN:
        case IPSECDOI_ID_USER_FQDN:
@@ -1680,8 +1765,7 @@ oakley_check_certid(iph1)
                int pos;
 
                for (pos = 1; ; pos++) {
-                       if (eay_get_x509subjectaltname(&iph1->cert_p->cert,
-                                       &altname, &type, pos) != 0){
+                       if (eay_get_x509subjectaltname(&cert_p->cert, &altname, &type, pos, &len) != 0) {
                                plog(LLV_ERROR, LOCATION, NULL,
                                        "failed to get subjectAltName\n");
                                return ISAKMP_NTYPE_INVALID_CERTIFICATE;
@@ -1689,47 +1773,37 @@ oakley_check_certid(iph1)
 
                        /* it's the end condition of the loop. */
                        if (!altname) {
-                               plog(LLV_ERROR, LOCATION, NULL,
-                                       "no proper subjectAltName.\n");
-                               return ISAKMP_NTYPE_INVALID_CERTIFICATE;
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
                        }
 
-                       if (check_typeofcertname(id_b->type, type) == 0)
-                               break;
+                       if (check_typeofcertname(idtype, type) != 0) {
+                               /* wrong general type - skip this one */
+                               racoon_free(altname);
+                               altname = NULL;
+                               continue;
+                       }
 
-                       /* next name */
-                       racoon_free(altname);
-                       altname = NULL;
-               }
-               if (idlen != strlen(altname)) {
-                       plog(LLV_ERROR, LOCATION, NULL,
-                               "Invalid ID length in phase 1.\n");
-                       racoon_free(altname);
-                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
-               }
-               if (check_typeofcertname(id_b->type, type) != 0) {
-                       plog(LLV_ERROR, LOCATION, NULL,
-                               "ID type mismatched. ID: %s CERT: %s.\n",
-                               s_ipsecdoi_ident(id_b->type),
-                               s_ipsecdoi_ident(type));
-                       racoon_free(altname);
-                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
-               }
-               error = memcmp(id_b + 1, altname, idlen);
-               if (error) {
-                       plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n");
+                       if (idlen != strlen(altname)) {
+                               /* wrong length - skip this one */
+                               racoon_free(altname);
+                               altname = NULL;
+                               continue;
+                       }
+                       error = memcmp(id, altname, idlen);
                        racoon_free(altname);
-                       return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       if (error) {
+                               plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n");
+                               return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
+                       }
+                       return 0;
                }
-               racoon_free(altname);
-               return 0;
        }
        default:
                plog(LLV_ERROR, LOCATION, NULL,
                        "Inpropper ID type passed: %s.\n",
-                       s_ipsecdoi_ident(id_b->type));
+                       s_ipsecdoi_ident(idtype));
                return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
-       }
+       }       
        /*NOTREACHED*/
 }
 
@@ -2026,7 +2100,28 @@ oakley_skeyid(iph1)
        /* SKEYID */
        switch(iph1->approval->authmethod) {
        case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
-               if (iph1->etype != ISAKMP_ETYPE_IDENT) {
+                               if (iph1->nonce_p == NULL) {
+                                       plog(LLV_ERROR, LOCATION, NULL,
+                                               "no nonce payload received from peer.\n");
+                                       goto end;
+                               }
+                /* if we have a preshared key defined, just use it */
+                if (iph1->rmconf->shared_secret) {
+
+                       switch (iph1->rmconf->secrettype) {
+                               case SECRETTYPE_KEY:
+                                       iph1->authstr = getpsk(iph1->rmconf->shared_secret->v, iph1->rmconf->shared_secret->l-1);
+                                       break;
+                               case SECRETTYPE_KEYCHAIN:
+                                       iph1->authstr = getpskfromkeychain(iph1->rmconf->shared_secret->v);
+                                       break;
+                               case SECRETTYPE_USE:
+                               default:
+                                       iph1->authstr = vdup(iph1->rmconf->shared_secret);
+                       }
+
+               }
+               else if (iph1->etype != ISAKMP_ETYPE_IDENT) {
                        iph1->authstr = getpskbyname(iph1->id_p);
                        if (iph1->authstr == NULL) {
                                if (iph1->rmconf->verify_identifier) {
@@ -2090,6 +2185,11 @@ oakley_skeyid(iph1)
 #ifdef HAVE_GSSAPI
        case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB:
 #endif
+               if (iph1->nonce_p == NULL) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                               "no nonce payload received from peer.\n");
+                       goto end;
+               }
                len = iph1->nonce->l + iph1->nonce_p->l;
                buf = vmalloc(len);
                if (buf == NULL) {
@@ -2769,7 +2869,7 @@ oakley_do_encrypt(iph1, msg, ivep, ivp)
                char *p = &buf->v[len];
                if (lcconf->pad_random) {
                        for (i = 0; i < padlen; i++)
-                               *p++ = (char)random();
+                               *p++ = arc4random() & 0xff;
                }
         }
         memcpy(buf->v, pl, len);
@@ -2845,7 +2945,8 @@ oakley_padlen(len, base)
        padlen = base - len % base;
 
        if (lcconf->pad_randomlen)
-               padlen += ((random() % (lcconf->pad_maxsize + 1) + 1) * base);
+               padlen += ((arc4random() % (lcconf->pad_maxsize + 1) + 1) *
+                   base);
 
        return padlen;
 }