This commit is contained in:
Martin Willi
2006-04-28 10:51:19 +00:00
parent 51c3484a9f
commit 1029d84d23
514 changed files with 2 additions and 2 deletions
+184
View File
@@ -0,0 +1,184 @@
# Makefile for the scepclient
# Copyright (C) 2005 Jan Hutter, Martin Willi
# Hochschule fuer Technik Rapperswil
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
FREESWANSRCDIR=../..
include ${FREESWANSRCDIR}/Makefile.inc
PLUTODIR=../pluto
OPENACDIR=../openac
PROGRAM=scepclient
EXTRA8PROC=${PROGRAM}.8
LIBS=${FREESWANLIB} $(LIBDESLITE) -lgmp
CFLAGS+= -DDEBUG -DNO_PLUTO
# This compile option activates the leak detective
ifeq ($(USE_LEAK_DETECTIVE),true)
CFLAGS+= -DLEAK_DETECTIVE
endif
# This compile option activates dynamic URL fetching using libcurl
ifeq ($(USE_LIBCURL),true)
CFLAGS+= -DLIBCURL
LIBS+= -lcurl
endif
X509_OBJS= asn1.o ca.o certs.o constants.o crl.o defs.o fetch.o id.o keys.o \
lex.o md2.o md5.o mp_defs.o ocsp.o oid.o pem.o pgp.o pkcs1.o pkcs7.o \
rnd.o sha1.o smartcard.o x509.o
OBJS= rsakey.o pkcs10.o loglite.o scep.o ${X509_OBJS}
include ../Makefile.program
loglite.o : $(OPENACDIR)/loglite.c $(PLUTODIR)/log.h
$(CC) $(CFLAGS) -c -o $@ $<
rsakey.o : rsakey.c rsakey.h
$(CC) $(CFLAGS) -c -o $@ $<
pkcs10.o : pkcs10.c pkcs10.h
$(CC) $(CFLAGS) -c -o $@ $<
scep.o : scep.c scep.h
$(CC) $(CFLAGS) -c -o $@ $<
# X.509 library
asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
$(CC) $(CFLAGS) -c -o $@ $<
ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
$(CC) $(CFLAGS) -c -o $@ $<
crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
$(CC) $(CFLAGS) -c -o $@ $<
certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
$(CC) $(CFLAGS) -c -o $@ $<
constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
$(CC) $(CFLAGS) -c -o $@ $<
defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
$(CC) $(CFLAGS) -c -o $@ $<
fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
$(CC) $(CFLAGS) -c -o $@ $<
id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
$(CC) $(CFLAGS) -c -o $@ $<
keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
$(CC) $(CFLAGS) -c -o $@ $<
lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
$(CC) $(CFLAGS) -c -o $@ $<
md2.o : $(PLUTODIR)/md2.c $(PLUTODIR)/md2.h
$(CC) $(CFLAGS) -c -o $@ $<
md5.o : $(PLUTODIR)/md5.c $(PLUTODIR)/md5.h
$(CC) $(CFLAGS) -c -o $@ $<
mp_defs.o : $(PLUTODIR)/mp_defs.c $(PLUTODIR)/mp_defs.h
$(CC) $(CFLAGS) -c -o $@ $<
ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
$(CC) $(CFLAGS) -c -o $@ $<
oid.o : $(PLUTODIR)/oid.c $(PLUTODIR)/oid.h
$(CC) $(CFLAGS) -c -o $@ $<
pem.o : $(PLUTODIR)/pem.c $(PLUTODIR)/pem.h
$(CC) $(CFLAGS) -c -o $@ $<
pgp.o : $(PLUTODIR)/pgp.c $(PLUTODIR)/pgp.h
$(CC) $(CFLAGS) -c -o $@ $<
pkcs1.o : $(PLUTODIR)/pkcs1.c $(PLUTODIR)/pkcs1.h
$(CC) $(CFLAGS) -c -o $@ $<
pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
$(CC) $(CFLAGS) -c -o $@ $<
rnd.o : $(PLUTODIR)/rnd.c $(PLUTODIR)/rnd.h
$(CC) $(CFLAGS) -c -o $@ $<
sha1.o : $(PLUTODIR)/sha1.c $(PLUTODIR)/sha1.h
$(CC) $(CFLAGS) -c -o $@ $<
smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
$(CC) $(CFLAGS) -c -o $@ $<
x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
$(CC) $(CFLAGS) -c -o $@ $<
doxygen :
doxygen doxyconfig.DoxyFile
# Stolen from pluto/Makefile
gatherdeps:
@ls | grep '\.c$$' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
@echo
@ls | grep '\.c$$' | xargs grep '^#[ ]*include[ ]*"' | \
sed -e 's/\.c:#[ ]*include[ ]*"/.o: /' -e 's/".*//'
# Dependencies generated by "make gatherdeps":
pkcs10.o: pkcs10.c
rsakey.o: rsakey.c
scep.o: scep.c
scepclient.o: scepclient.c
pkcs10.o: ../pluto/constants.h
pkcs10.o: ../pluto/defs.h
pkcs10.o: ../pluto/oid.h
pkcs10.o: ../pluto/asn1.h
pkcs10.o: ../pluto/pkcs1.h
pkcs10.o: ../pluto/log.h
pkcs10.o: ../pluto/x509.h
pkcs10.o: pkcs10.h
rsakey.o: ../pluto/constants.h
rsakey.o: ../pluto/defs.h
rsakey.o: ../pluto/mp_defs.h
rsakey.o: ../pluto/log.h
rsakey.o: ../pluto/asn1.h
rsakey.o: ../pluto/pkcs1.h
rsakey.o: rsakey.h
scep.o: ../pluto/constants.h
scep.o: ../pluto/defs.h
scep.o: ../pluto/rnd.h
scep.o: ../pluto/oid.h
scep.o: ../pluto/asn1.h
scep.o: ../pluto/pkcs1.h
scep.o: ../pluto/fetch.h
scep.o: ../pluto/log.h
scep.o: scep.h
scepclient.o: ../pluto/constants.h
scepclient.o: ../pluto/defs.h
scepclient.o: ../pluto/log.h
scepclient.o: ../pluto/oid.h
scepclient.o: ../pluto/asn1.h
scepclient.o: ../pluto/pkcs1.h
scepclient.o: ../pluto/pkcs7.h
scepclient.o: ../pluto/certs.h
scepclient.o: ../pluto/fetch.h
scepclient.o: ../pluto/rnd.h
scepclient.o: rsakey.h
scepclient.o: pkcs10.h
scepclient.o: scep.h
+220
View File
@@ -0,0 +1,220 @@
/**
* @file pkcs10.c
* @brief Functions to build PKCS#10 requests
*
* Contains functions to build DER encoded pkcs#10 certificate requests
*/
/* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <freeswan.h>
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/oid.h"
#include "../pluto/asn1.h"
#include "../pluto/pkcs1.h"
#include "../pluto/log.h"
#include "../pluto/x509.h"
#include "pkcs10.h"
/* some pre-coded OIDs */
static u_char ASN1_challengePassword_oid_str[] = {
0x06,0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x07
};
static const chunk_t ASN1_challengePassword_oid = strchunk(ASN1_challengePassword_oid_str);
static u_char ASN1_extensionRequest_oid_str[] = {
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E
};
static const chunk_t ASN1_extensionRequest_oid = strchunk(ASN1_extensionRequest_oid_str);
/**
* @brief Adds a subjectAltName in DER-coded form to a linked list
*
* @param[in,out] subjectAltNames head of the linked list of subjectAltNames
* @param[in] kind type of the subjectAltName (which is a generalName)
* @param[in] value value of the subjectAltName as an ASCII string
*/
void
pkcs10_add_subjectAltName(generalName_t **subjectAltNames, generalNames_t kind
, char *value)
{
generalName_t *gn;
asn1_t asn1_type = ASN1_EOC;
chunk_t name = { value, strlen(value) };
switch (kind)
{
case GN_RFC822_NAME:
asn1_type = ASN1_CONTEXT_S_1;
break;
case GN_DNS_NAME:
asn1_type = ASN1_CONTEXT_S_2;
break;
case GN_IP_ADDRESS:
{
struct in_addr addr;
/* convert an ASCII dotted IPv4 address (e.g. 123.456.78.90)
* to a byte representation in network order
*/
if (!inet_aton(value, &addr))
{
fprintf(stderr, "error in IPv4 subjectAltName\n");
return;
}
asn1_type = ASN1_CONTEXT_S_7;
name.ptr = (u_char *) &addr.s_addr;
name.len = sizeof(addr.s_addr);
break;
}
default:
break;
}
gn = alloc_thing(generalName_t, "subjectAltName");
gn->kind = kind;
gn->name = asn1_simple_object(asn1_type, name);
gn->next = *subjectAltNames;
*subjectAltNames = gn;
}
/**
* @brief Builds the requestInfoAttributes of the certificationRequestInfo-field
*
* challenge password ans subjectAltNames are only included,
* when avaiable in given #pkcs10_t structure
*
* @param[in] pkcs10 Pointer to a #pkcs10_t structure
* @return 1 if succeeded, 0 otherwise
*/
static chunk_t
build_req_info_attributes(pkcs10_t* pkcs10)
{
chunk_t subjectAltNames = empty_chunk;
chunk_t challengePassword = empty_chunk;
if (pkcs10->subjectAltNames != NULL)
{
subjectAltNames = asn1_wrap(ASN1_SEQUENCE, "cm"
, ASN1_extensionRequest_oid
, asn1_wrap(ASN1_SET, "m"
, asn1_wrap(ASN1_SEQUENCE, "m"
, build_subjectAltNames(pkcs10->subjectAltNames)
)
)
);
}
if (pkcs10->challengePassword.len > 0)
{
asn1_t type = is_printablestring(pkcs10->challengePassword)
? ASN1_PRINTABLESTRING : ASN1_T61STRING;
challengePassword = asn1_wrap(ASN1_SEQUENCE, "cm"
, ASN1_challengePassword_oid
, asn1_wrap(ASN1_SET, "m"
, asn1_simple_object(type, pkcs10->challengePassword)
)
);
}
return asn1_wrap(ASN1_CONTEXT_C_0, "mm"
, subjectAltNames
, challengePassword);
}
/**
* @brief Builds a DER-code pkcs#10 certificate request
*
* @param[in] pkcs10 pointer to a pkcs10_t struct
* @return DER-code pkcs10 request
*/
static chunk_t
pkcs10_build_request(pkcs10_t *pkcs10, int signature_alg)
{
RSA_public_key_t *rsak = (RSA_public_key_t *) pkcs10->private_key;
chunk_t cert_req_info = asn1_wrap(ASN1_SEQUENCE, "ccmm"
, ASN1_INTEGER_0
, pkcs10->subject
, pkcs1_build_publicKeyInfo(rsak)
, build_req_info_attributes(pkcs10));
chunk_t signature = pkcs1_build_signature(cert_req_info
, signature_alg, pkcs10->private_key, TRUE);
return asn1_wrap(ASN1_SEQUENCE, "mcm"
, cert_req_info
, asn1_algorithmIdentifier(signature_alg)
, signature);
}
/**
* @brief Creates a pkcs#10 certificate request object
*
* To create a certificate request, the RSA key and the
* names to be included as subject in the certificate request
* (e.g. commonName, organization) are needed. An optional challenge
* password or some subjectAltNames may be included.
*
* @param[in] key rsakey of type #rsakey_t
* @param[in] subject DER-coded subject distinguished name
* @param[in] challengePassword challenge password or empty_chunk
* @param[in] subjectAltNames linked list of subjectAltNames or NULL
* @return pointer to a #pkcs10_t object
*/
pkcs10_t*
pkcs10_build(RSA_private_key_t *key, chunk_t subject, chunk_t challengePassword
, generalName_t *subjectAltNames, int signature_alg)
{
pkcs10_t *pkcs10 = alloc_thing(pkcs10_t, "pkcs10_t");
pkcs10->subject = subject;
pkcs10->private_key = key;
pkcs10->challengePassword = challengePassword;
pkcs10->subjectAltNames = subjectAltNames;
pkcs10->request = pkcs10_build_request(pkcs10, signature_alg);
return pkcs10;
}
/**
* @brief Frees the resources used by an #pkcs10_t object
*
* @param[in] pkcs10 #pkcs10_t to free
*/
void
pkcs10_free(pkcs10_t *pkcs10)
{
if (pkcs10 != NULL)
{
freeanychunk(pkcs10->request);
pfree(pkcs10);
}
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file pkcs10.h
* @brief Functions to build PKCS#10 Request's
*
* Contains functions to build DER encoded pkcs#10 certificate requests
*/
/*
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef _PKCS10_H
#define _PKCS10_H
#include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/x509.h"
typedef struct pkcs10_struct pkcs10_t;
/**
* @brief type representating a pkcs#10 request.
*
* A pkcs#10 request contains a distinguished name, an optional
* challenge password, a public key and optional subjectAltNames.
*
* The RSA private key is needed to compute the signature of the given request
*/
struct pkcs10_struct {
RSA_private_key_t *private_key;
chunk_t request;
chunk_t subject;
chunk_t challengePassword;
generalName_t *subjectAltNames;
};
extern const pkcs10_t empty_pkcs10;
extern void pkcs10_add_subjectAltName(generalName_t **subjectAltNames
, generalNames_t kind, char *value);
extern pkcs10_t* pkcs10_build(RSA_private_key_t *key, chunk_t subject
, chunk_t challengePassword, generalName_t *subjectAltNames
, int signature_alg);
extern void pkcs10_free(pkcs10_t *pkcs10);
#endif /* _PKCS10_H */
+349
View File
@@ -0,0 +1,349 @@
/**
* @file rsakey.c
* @brief Functions for RSA key generation
*/
/*
* Copyright (C) 1999, 2000, 2001 Henry Spencer.
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* $Id: rsakey.c,v 1.5 2006/01/04 21:16:30 as Exp $
*/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <gmp.h>
#include <freeswan.h>
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/mp_defs.h"
#include "../pluto/log.h"
#include "../pluto/asn1.h"
#include "../pluto/pkcs1.h"
#include "rsakey.h"
/* Number of times the probabilistic primality test is applied */
#define PRIMECHECK_ROUNDS 30
/* Public exponent used for signature key generation */
#define PUBLIC_EXPONENT 0x10001
#ifndef RANDOM_DEVICE
#define RANDOM_DEVICE "/dev/random"
#endif
/**
* @brief Reads a specific number of bytes from a given device/file
*
* @param[in] nbytes number of bytes to read from random device
* @param[out] buf pointer to buffer where to write the data in.
* size of buffer has to be at least nbytes.
* @return TRUE, if succeeded, FALSE otherwise
*/
static bool
get_true_random_bytes(size_t nbytes, char *buf)
{
size_t ndone;
size_t got;
char *device = RANDOM_DEVICE;
int dev = open(RANDOM_DEVICE, 0);
if (dev < 0)
{
fprintf(stderr, "could not open random device %s", device);
return FALSE;
}
DBG(DBG_CONTROL,
DBG_log("getting %d bytes from %s...", (int) nbytes, device)
)
ndone = 0;
while (ndone < nbytes)
{
got = read(dev, buf + ndone, nbytes - ndone);
if (got < 0)
{
fprintf(stderr, "read error on %s", device);
return FALSE;
}
if (got == 0)
{
fprintf(stderr, "eof on %s", device);
return FALSE;
}
ndone += got;
}
close(dev);
return TRUE;
}
/**
* @brief initialize an mpz_t to a random number, specified bit count
*
* Converting the random value in a value of type mpz_t is done
* by creating a hexbuffer.
* Converting via hex is a bit weird, but it's the best route GMP gives us.
* Note that highmost and lowmost bits are forced on -- highmost to give a
* number of exactly the specified length, lowmost so it is an odd number.
*
* @param[out] var uninitialized mpz_t to store th random number in
* @param[in] nbits length of var in bits (known to be a multiple of BITS_PER_BYTE)
* @return TRUE on success, FALSE otherwise
*/
static bool
init_random(mpz_t var, int nbits)
{
size_t nbytes = (size_t)(nbits/BITS_PER_BYTE);
char random_buf[RSA_MAX_OCTETS/2];
assert(nbytes <= sizeof(random_buf));
if (!get_true_random_bytes(nbytes, random_buf))
return FALSE;
random_buf[0] |= 01 << (BITS_PER_BYTE-1); /* force high bit on */
random_buf[nbytes-1] |= 01; /* force low bit on */
n_to_mpz(var, random_buf, nbytes);
return TRUE;
}
/**
* @brief initialize an mpz_t to a random prime of specified size
*
* Efficiency tweak: we reject candidates that are 1 higher than a multiple
* of e, since they will make the internal modulus not relatively prime to e.
*
* @param[out] var mpz_t variable to initialize
* @param[in] nbits length of given prime in bits (known to be a multiple of BITS_PER_BYTE)
* @param[in] eval E-Value, 0 means don't bother w. tweak
* @return 1 on success, 0 otherwise
*/
static bool
init_prime(mpz_t var, int nbits, int eval)
{
unsigned long tries;
size_t len;
/* get a random value of nbits length */
if (!init_random(var, nbits))
return FALSE;
/* check if odd number */
assert(mpz_fdiv_ui(var, 2) == 1);
DBG(DBG_CONTROLMORE,
DBG_log("looking for a prime starting there (can take a while)...")
)
tries = 1;
while (mpz_fdiv_ui(var, eval) == 1
|| !mpz_probab_prime_p(var, PRIMECHECK_ROUNDS))
{
/* not a prime, increase by 2 */
mpz_add_ui(var, var, 2);
tries++;
}
len = mpz_sizeinbase(var, 2);
/* check bit length of primee */
assert(len == (size_t)nbits || len == (size_t)(nbits+1));
if (len == (size_t)(nbits+1))
{
DBG(DBG_CONTROLMORE,
DBG_log("carry out occurred (!), retrying...")
)
mpz_clear(var);
/* recursive call */
return init_prime(var, nbits, eval);
}
DBG(DBG_CONTROLMORE,
DBG_log("found it after %lu tries.",tries)
)
return TRUE;
}
/**
* @brief Generate a RSA key usable for encryption
*
* Generate an RSA key usable for encryption. All the
* values of the RSA key are filled into mpz_t parameters.
* These mpz_t parameters must not be initialized and have
* to be cleared with mpz_clear after using.
*
* @param[in] nbits size of rsa key in bits
* @return RSA_public_key_t containing the generated RSA key
*/
err_t
generate_rsa_private_key(int nbits, RSA_private_key_t *key)
{
mpz_t p, q, n, e, d, exp1, exp2, coeff;
mpz_t m, q1, t; /* temporary variables*/
DBG(DBG_CONTROL,
DBG_log("generating %d bit RSA key:", nbits)
)
if (nbits <= 0)
return "negative rsa key length!";
/* Get values of primes p and q */
DBG(DBG_CONTROLMORE,
DBG_log("initialize prime p")
)
if (!init_prime(p, nbits/2, PUBLIC_EXPONENT))
return "could not generate prime p";
DBG(DBG_CONTROLMORE,
DBG_log("initialize prime q")
)
if (!init_prime(q, nbits/2, PUBLIC_EXPONENT))
return "could not generate prime q";
mpz_init(t);
/* Swapping primes so p is larger then q */
if (mpz_cmp(p, q) < 0)
{
DBG(DBG_CONTROLMORE,
DBG_log("swapping primes so p is the larger...")
);
mpz_set(t, p);
mpz_set(p, q);
mpz_set(q, t);
}
DBG(DBG_CONTROLMORE,
DBG_log("computing modulus...")
)
mpz_init(n);
/* n = p*q */
mpz_mul(n, p, q);
/* Assign e the value of defined PUBLIC_EXPONENT */
mpz_init_set_ui(e, PUBLIC_EXPONENT);
DBG(DBG_CONTROLMORE,
DBG_log("computing lcm(p-1, q-1)...")
)
/* m = p */
mpz_init_set(m, p);
/* m = m-1 */
mpz_sub_ui(m, m, 1);
/* q1 = q */
mpz_init_set(q1, q);
/* q1 = q1-1 */
mpz_sub_ui(q1, q1, 1);
/* t = gcd(p-1, q-1) */
mpz_gcd(t, m, q1);
/* m = (p-1)*(q-1) */
mpz_mul(m, m, q1);
/* m = m / t */
mpz_divexact(m, m, t);
/* t = gcd(m, e) (greatest common divisor) */
mpz_gcd(t, m, e);
/* m and e relatively prime */
assert(mpz_cmp_ui(t, 1) == 0);
/* decryption key */
DBG(DBG_CONTROLMORE,
DBG_log("computing d...")
)
mpz_init(d);
/* e has an inverse mod m */
assert(mpz_invert(d, e, m));
/* make sure d is positive */
if (mpz_cmp_ui(d, 0) < 0)
mpz_add(d, d, m);
/* d has to be positive */
assert(mpz_cmp(d, m) < 0);
/* the speedup hacks */
DBG(DBG_CONTROLMORE,
DBG_log("computing exp1, exp1, coeff...")
)
mpz_init(exp1);
/* t = p-1 */
mpz_sub_ui(t, p, 1);
/* exp1 = d mod p-1 */
mpz_mod(exp1, d, t);
mpz_init(exp2);
/* t = q-1 */
mpz_sub_ui(t, q, 1);
/* exp2 = d mod q-1 */
mpz_mod(exp2, d, t);
mpz_init(coeff);
/* coeff = q^-1 mod p */
mpz_invert(coeff, q, p);
/* make sure coeff is positive */
if (mpz_cmp_ui(coeff, 0) < 0)
mpz_add(coeff, coeff, p);
/* coeff has to be positive */
assert(mpz_cmp(coeff, p) < 0);
/* Clear temporary variables */
mpz_clear(q1);
mpz_clear(m);
mpz_clear(t);
/* form FreeS/WAN keyid */
{
size_t e_len = (mpz_sizeinbase(e,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
size_t n_len = (mpz_sizeinbase(n,2)+BITS_PER_BYTE-1)/BITS_PER_BYTE;
chunk_t e_ch = mpz_to_n(e, e_len);
chunk_t n_ch = mpz_to_n(n, n_len);
form_keyid(e_ch, n_ch, key->pub.keyid, &key->pub.k);
freeanychunk(e_ch);
freeanychunk(n_ch);
}
/* fill in the elements of the RSA private key */
key->p = *p;
key->q = *q;
key->pub.n = *n;
key->pub.e = *e;
key->d = *d;
key->dP = *exp1;
key->dQ = *exp2;
key->qInv = *coeff;
DBG(DBG_CONTROL,
DBG_log("RSA key *%s generated with %d bits", key->pub.keyid
, (int)mpz_sizeinbase(n,2))
)
#ifdef DEBUG
DBG(DBG_PRIVATE,
RSA_show_private_key(key)
)
#endif
return NULL;
}
+31
View File
@@ -0,0 +1,31 @@
/**
* @file rsakey.h
* @brief Functions for RSA key generation
*/
/*
* Copyright (C) 1999, 2000, 2001 Henry Spencer.
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* $Id: rsakey.h,v 1.2 2005/08/11 21:52:56 as Exp $
*/
#ifndef RSAKEY_H_
#define RSAKEY_H_
#include "../pluto/pkcs1.h"
extern err_t generate_rsa_private_key(int nbits, RSA_private_key_t *key);
#endif // RSAKEY_H_
+598
View File
@@ -0,0 +1,598 @@
/**
* @file scep.c
* @brief SCEP specific functions
*
* Contains functions to build SCEP request's and to parse SCEP reply's.
*/
/*
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <string.h>
#include <stdlib.h>
#include <freeswan.h>
#ifdef LIBCURL
#include <curl/curl.h>
#endif
#include "../pluto/constants.h"
#include "../pluto/defs.h"
#include "../pluto/rnd.h"
#include "../pluto/oid.h"
#include "../pluto/asn1.h"
#include "../pluto/pkcs1.h"
#include "../pluto/fetch.h"
#include "../pluto/log.h"
#include "scep.h"
static char ASN1_messageType_oid_str[] = {
0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02
};
static char ASN1_senderNonce_oid_str[] = {
0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05
};
static char ASN1_transId_oid_str[] = {
0x06, 0x0A, 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07
};
static const chunk_t ASN1_messageType_oid =
strchunk(ASN1_messageType_oid_str);
static const chunk_t ASN1_senderNonce_oid =
strchunk(ASN1_senderNonce_oid_str);
static const chunk_t ASN1_transId_oid =
strchunk(ASN1_transId_oid_str);
static const char *pkiStatus_values[] = { "0", "2", "3" };
static const char *pkiStatus_names[] = {
"SUCCESS",
"FAILURE",
"PENDING",
"UNKNOWN"
};
static const char *msgType_values[] = { "3", "19", "20", "21", "22" };
static const char *msgType_names[] = {
"CertRep",
"PKCSReq",
"GetCertInitial",
"GetCert",
"GetCRL",
"Unknown"
};
static const char *failInfo_reasons[] = {
"badAlg - unrecognized or unsupported algorithm identifier",
"badMessageCheck - integrity check failed",
"badRequest - transaction not permitted or supported",
"badTime - Message time field was not sufficiently close to the system time",
"badCertId - No certificate could be identified matching the provided criteria"
};
const scep_attributes_t empty_scep_attributes = {
SCEP_Unknown_MSG , /* msgType */
SCEP_UNKNOWN , /* pkiStatus */
SCEP_unknown_REASON, /* failInfo */
{ NULL, 0 } , /* transID */
{ NULL, 0 } , /* senderNonce */
{ NULL, 0 } , /* recipientNonce */
};
/* ASN.1 definition of the X.501 atttribute type */
static const asn1Object_t attributesObjects[] = {
{ 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
{ 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
{ 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
{ 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
{ 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
};
#define ATTRIBUTE_OBJ_TYPE 2
#define ATTRIBUTE_OBJ_VALUE 4
#define ATTRIBUTE_OBJ_ROOF 7
/*
* extract and store an attribute
*/
static bool
extract_attribute(int oid, chunk_t object, u_int level
, scep_attributes_t *attrs)
{
asn1_t type = ASN1_EOC;
const char *name = "none";
switch (oid)
{
case OID_PKCS9_CONTENT_TYPE:
type = ASN1_OID;
name = "contentType";
break;
case OID_PKCS9_SIGNING_TIME:
type = ASN1_UTCTIME;
name = "signingTime";
break;
case OID_PKCS9_MESSAGE_DIGEST:
type = ASN1_OCTET_STRING;
name = "messageDigest";
break;
case OID_PKI_MESSAGE_TYPE:
type = ASN1_PRINTABLESTRING;
name = "messageType";
break;
case OID_PKI_STATUS:
type = ASN1_PRINTABLESTRING;
name = "pkiStatus";
break;
case OID_PKI_FAIL_INFO:
type = ASN1_PRINTABLESTRING;
name = "failInfo";
break;
case OID_PKI_SENDER_NONCE:
type = ASN1_OCTET_STRING;
name = "senderNonce";
break;
case OID_PKI_RECIPIENT_NONCE:
type = ASN1_OCTET_STRING;
name = "recipientNonce";
break;
case OID_PKI_TRANS_ID:
type = ASN1_PRINTABLESTRING;
name = "transID";
break;
default:
break;
}
if (type == ASN1_EOC)
return TRUE;
if (!parse_asn1_simple_object(&object, type, level+1, name))
return FALSE;
switch (oid)
{
case OID_PKCS9_CONTENT_TYPE:
break;
case OID_PKCS9_SIGNING_TIME:
break;
case OID_PKCS9_MESSAGE_DIGEST:
break;
case OID_PKI_MESSAGE_TYPE:
{
scep_msg_t m;
for (m = SCEP_CertRep_MSG; m < SCEP_Unknown_MSG; m++)
{
if (strncmp(msgType_values[m], object.ptr, object.len) == 0)
attrs->msgType = m;
}
DBG(DBG_CONTROL,
DBG_log("messageType: %s", msgType_names[attrs->msgType])
)
}
break;
case OID_PKI_STATUS:
{
pkiStatus_t s;
for (s = SCEP_SUCCESS; s < SCEP_UNKNOWN; s++)
{
if (strncmp(pkiStatus_values[s], object.ptr, object.len) == 0)
attrs->pkiStatus = s;
}
DBG(DBG_CONTROL,
DBG_log("pkiStatus: %s", pkiStatus_names[attrs->pkiStatus])
)
}
break;
case OID_PKI_FAIL_INFO:
if (object.len == 1
&& *object.ptr >= '0' && *object.ptr <= '4')
{
attrs->failInfo = (failInfo_t)(*object.ptr - '0');
}
if (attrs->failInfo != SCEP_unknown_REASON)
plog("failInfo: %s", failInfo_reasons[attrs->failInfo]);
break;
case OID_PKI_SENDER_NONCE:
attrs->senderNonce = object;
break;
case OID_PKI_RECIPIENT_NONCE:
attrs->recipientNonce = object;
break;
case OID_PKI_TRANS_ID:
attrs->transID = object;
}
return TRUE;
}
/*
* parse X.501 attributes
*/
bool
parse_attributes(chunk_t blob, scep_attributes_t *attrs)
{
asn1_ctx_t ctx;
chunk_t object;
u_int level;
int oid = OID_UNKNOWN;
int objectID = 0;
asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
DBG(DBG_CONTROL | DBG_PARSING,
DBG_log("parsing attributes")
)
while (objectID < ATTRIBUTE_OBJ_ROOF)
{
if (!extract_object(attributesObjects, &objectID
, &object, &level, &ctx))
return FALSE;
switch (objectID)
{
case ATTRIBUTE_OBJ_TYPE:
oid = known_oid(object);
break;
case ATTRIBUTE_OBJ_VALUE:
if (!extract_attribute(oid, object, level, attrs))
return FALSE;
}
objectID++;
}
return TRUE;
}
/* generates a unique fingerprint of the pkcs10 request
* by computing an MD5 hash over it
*/
void
scep_generate_pkcs10_fingerprint(chunk_t pkcs10, chunk_t *fingerprint)
{
char buf[MD5_DIGEST_SIZE];
chunk_t digest = { buf, sizeof(buf) };
/* the fingerprint is the MD5 hash in hexadecimal format */
compute_digest(pkcs10, OID_MD5, &digest);
fingerprint->len = 2*digest.len;
fingerprint->ptr = alloc_bytes(fingerprint->len + 1, "fingerprint");
datatot(digest.ptr, digest.len, 16, fingerprint->ptr, fingerprint->len + 1);
}
/* generate a transaction id as the MD5 hash of an public key
* the transaction id is also used as a unique serial number
*/
void
scep_generate_transaction_id(const RSA_public_key_t *rsak
, chunk_t *transID, chunk_t *serialNumber)
{
char buf[MD5_DIGEST_SIZE];
chunk_t digest = { buf, sizeof(buf) };
chunk_t public_key = pkcs1_build_publicKeyInfo(rsak);
bool msb_set;
u_char *pos;
compute_digest(public_key, OID_MD5, &digest);
pfree(public_key.ptr);
/* is the most significant bit of the digest set? */
msb_set = (*digest.ptr & 0x80) == 0x80;
/* allocate space for the serialNumber */
serialNumber->len = msb_set + digest.len;
serialNumber->ptr = alloc_bytes(serialNumber->len, "serialNumber");
/* the serial number as the two's complement of the digest */
pos = serialNumber->ptr;
if (msb_set)
{
*pos++ = 0x00;
}
memcpy(pos, digest.ptr, digest.len);
/* the transaction id is the serial number in hex format */
transID->len = 2*digest.len;
transID->ptr = alloc_bytes(transID->len + 1, "transID");
datatot(digest.ptr, digest.len, 16, transID->ptr, transID->len + 1);
}
/*
* builds a transId attribute
*/
chunk_t
scep_transId_attribute(chunk_t transID)
{
return asn1_wrap(ASN1_SEQUENCE, "cm"
, ASN1_transId_oid
, asn1_wrap(ASN1_SET, "m"
, asn1_simple_object(ASN1_PRINTABLESTRING, transID)
)
);
}
/*
* builds a messageType attribute
*/
chunk_t
scep_messageType_attribute(scep_msg_t m)
{
chunk_t msgType = {
msgType_values[m],
strlen(msgType_values[m])
};
return asn1_wrap(ASN1_SEQUENCE, "cm"
, ASN1_messageType_oid
, asn1_wrap(ASN1_SET, "m"
, asn1_simple_object(ASN1_PRINTABLESTRING, msgType)
)
);
}
/*
* builds a senderNonce attribute
*/
chunk_t
scep_senderNonce_attribute(void)
{
const size_t nonce_len = 16;
u_char nonce_buf[nonce_len];
chunk_t senderNonce = { nonce_buf, nonce_len };
get_rnd_bytes(nonce_buf, nonce_len);
return asn1_wrap(ASN1_SEQUENCE, "cm"
, ASN1_senderNonce_oid
, asn1_wrap(ASN1_SET, "m"
, asn1_simple_object(ASN1_OCTET_STRING, senderNonce)
)
);
}
/*
* builds a pkcs7 enveloped and signed scep request
*/
chunk_t
scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg
, const x509cert_t *enc_cert, int enc_alg
, const x509cert_t *signer_cert, int digest_alg
, const RSA_private_key_t *private_key)
{
chunk_t envelopedData, attributes, request;
envelopedData = pkcs7_build_envelopedData(data, enc_cert, enc_alg);
attributes = asn1_wrap(ASN1_SET, "mmmmm"
, pkcs7_contentType_attribute()
, pkcs7_messageDigest_attribute(envelopedData
, digest_alg)
, scep_transId_attribute(transID)
, scep_messageType_attribute(msg)
, scep_senderNonce_attribute());
request = pkcs7_build_signedData(envelopedData, attributes
, signer_cert, digest_alg, private_key);
freeanychunk(envelopedData);
freeanychunk(attributes);
return request;
}
#ifdef LIBCURL
/* converts a binary request to base64 with 64 characters per line
* newline and '+' characters are escaped by %0A and %2B, respectively
*/
static char*
escape_http_request(chunk_t req)
{
char *escaped_req = NULL;
char *p1, *p2;
int lines = 0;
int plus = 0;
int n = 0;
/* compute and allocate the size of the base64-encoded request */
int len = 1 + 4*((req.len + 2)/3);
char *encoded_req = alloc_bytes(len, "encoded request");
/* do the base64 conversion */
len = datatot(req.ptr, req.len, 64, encoded_req, len);
/* compute newline characters to be inserted every 64 characters */
lines = (len - 2) / 64;
/* count number of + characters to be escaped */
p1 = encoded_req;
while (*p1 != '\0')
{
if (*p1++ == '+')
plus++;
}
escaped_req = alloc_bytes(len + 3*(lines + plus), "escaped request");
/* escape special characters in the request */
p1 = encoded_req;
p2 = escaped_req;
while (*p1 != '\0')
{
if (n == 64)
{
memcpy(p2, "%0A", 3);
p2 += 3;
n = 0;
}
if (*p1 == '+')
{
memcpy(p2, "%2B", 3);
p2 += 3;
}
else
{
*p2++ = *p1;
}
p1++;
n++;
}
*p2 = '\0';
pfreeany(encoded_req);
return escaped_req;
}
#endif
/*
* send a SCEP request via HTTP and wait for a response
*/
bool
scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op
, fetch_request_t req_type, chunk_t *response)
{
#ifdef LIBCURL
char errorbuffer[CURL_ERROR_SIZE] = "";
char *complete_url = NULL;
struct curl_slist *headers = NULL;
CURL *curl;
CURLcode res;
/* initialize response */
*response = empty_chunk;
/* initialize curl context */
curl = curl_easy_init();
if (curl == NULL)
{
plog("could not initialize curl context");
return FALSE;
}
if (op == SCEP_PKI_OPERATION)
{
const char operation[] = "PKIOperation";
if (req_type == FETCH_GET)
{
char *escaped_req = escape_http_request(pkcs7);
/* form complete url */
int len = strlen(url) + 20 + strlen(operation) + strlen(escaped_req) + 1;
complete_url = alloc_bytes(len, "complete url");
snprintf(complete_url, len, "%s?operation=%s&message=%s"
, url, operation, escaped_req);
pfreeany(escaped_req);
curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE);
headers = curl_slist_append(headers, "Pragma:");
headers = curl_slist_append(headers, "Host:");
headers = curl_slist_append(headers, "Accept:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
}
else /* HTTP_POST */
{
/* form complete url */
int len = strlen(url) + 11 + strlen(operation) + 1;
complete_url = alloc_bytes(len, "complete url");
snprintf(complete_url, len, "%s?operation=%s", url, operation);
curl_easy_setopt(curl, CURLOPT_HTTPGET, FALSE);
headers = curl_slist_append(headers, "Content-Type:");
headers = curl_slist_append(headers, "Expect:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pkcs7.ptr);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, pkcs7.len);
}
}
else /* SCEP_GET_CA_CERT */
{
const char operation[] = "GetCACert";
/* form complete url */
int len = strlen(url) + 32 + strlen(operation) + 1;
complete_url = alloc_bytes(len, "complete url");
snprintf(complete_url, len, "%s?operation=%s&message=CAIdentifier"
, url, operation);
curl_easy_setopt(curl, CURLOPT_HTTPGET, TRUE);
}
curl_easy_setopt(curl, CURLOPT_URL, complete_url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT);
DBG(DBG_CONTROL,
DBG_log("sending scep request to '%s'", url)
)
res = curl_easy_perform(curl);
if (res == CURLE_OK)
{
DBG(DBG_CONTROL,
DBG_log("received scep response")
)
DBG(DBG_RAW,
DBG_dump_chunk("SCEP response:\n", *response)
)
}
else
{
plog("failed to fetch scep response from '%s': %s", url, errorbuffer);
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
pfreeany(complete_url);
return (res == CURLE_OK);
#else /* !LIBCURL */
plog("scep error: pluto wasn't compiled with libcurl support");
return FALSE;
#endif /* !LIBCURL */
}
err_t
scep_parse_response(chunk_t response, chunk_t transID, contentInfo_t *data
, scep_attributes_t *attrs, x509cert_t *signer_cert)
{
chunk_t attributes;
if (!pkcs7_parse_signedData(response, data, NULL, &attributes, signer_cert))
{
return "error parsing the scep response";
}
if (!parse_attributes(attributes, attrs))
{
return "error parsing the scep response attributes";
}
if (!same_chunk(transID, attrs->transID))
{
return "transaction ID of scep response does not match";
}
return NULL;
}
+93
View File
@@ -0,0 +1,93 @@
/**
* @file scep.h
* @brief SCEP specific functions
*
* Contains functions to build and parse SCEP requests and replies
*/
/*
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef _SCEP_H
#define _SCEP_H
#include "../pluto/defs.h"
#include "../pluto/pkcs1.h"
#include "../pluto/pkcs7.h"
/* supported SCEP operation types */
typedef enum {
SCEP_PKI_OPERATION,
SCEP_GET_CA_CERT
} scep_op_t;
/* SCEP pkiStatus values */
typedef enum {
SCEP_SUCCESS,
SCEP_FAILURE,
SCEP_PENDING,
SCEP_UNKNOWN
} pkiStatus_t;
/* SCEP messageType values */
typedef enum {
SCEP_CertRep_MSG,
SCEP_PKCSReq_MSG,
SCEP_GetCertInitial_MSG,
SCEP_GetCert_MSG,
SCEP_GetCRL_MSG,
SCEP_Unknown_MSG
} scep_msg_t;
/* SCEP failure reasons */
typedef enum {
SCEP_badAlg_REASON = 0,
SCEP_badMessageCheck_REASON = 1,
SCEP_badRequest_REASON = 2,
SCEP_badTime_REASON = 3,
SCEP_badCertId_REASON = 4,
SCEP_unknown_REASON = 5
} failInfo_t;
/* SCEP attributes */
typedef struct {
scep_msg_t msgType;
pkiStatus_t pkiStatus;
failInfo_t failInfo;
chunk_t transID;
chunk_t senderNonce;
chunk_t recipientNonce;
} scep_attributes_t;
extern const scep_attributes_t empty_scep_attributes;
extern bool parse_attributes(chunk_t blob, scep_attributes_t *attrs);
extern void scep_generate_pkcs10_fingerprint(chunk_t pkcs10
, chunk_t *fingerprint);
extern void scep_generate_transaction_id(const RSA_public_key_t *rsak
, chunk_t *transID, chunk_t *serialNumber);
extern chunk_t scep_transId_attribute(chunk_t transaction_id);
extern chunk_t scep_messageType_attribute(scep_msg_t m);
extern chunk_t scep_senderNonce_attribute(void);
extern chunk_t scep_build_request(chunk_t data, chunk_t transID, scep_msg_t msg
, const x509cert_t *enc_cert, int enc_alg
, const x509cert_t *signer_cert, int digest_alg
, const RSA_private_key_t *private_key);
extern bool scep_http_request(const char *url, chunk_t pkcs7, scep_op_t op
, fetch_request_t request_type, chunk_t *response);
extern err_t scep_parse_response(chunk_t response, chunk_t transID
, contentInfo_t *data, scep_attributes_t *attrs, x509cert_t *signer_cert);
#endif /* _SCEP_H */
+288
View File
@@ -0,0 +1,288 @@
.\"
.TH "IPSEC_SCEPCLIENT" "8" "29 September 2005" "Jan Hutter, Martin Willi" ""
.SH "NAME"
ipsec scepclient \- Client for the SCEP protocol
.SH "SYNOPSIS"
.B ipsec scepclient [argument ...]
.sp
.B ipsec scepclient
.B \-\-help
.br
.B ipsec scepclient
.B \-\-version
.SH "DESCRIPTION"
.BR scepclient
is a client implementation of Cisco System's Simple Certificate Enrollment Protocol (SCEP) written for Linux strongSwan <http://www.strongswan.org>.
.BR scepclient
is designed to be used for certificate enrollment on machines using the OpenSource IPsec solution
.I strongSwan.
.SH "FEATURES"
.BR scepclient
implements the following features of SCEP:
.br
.IP "\-" 4
Automatic enrollment of client certificate using a preshared secret
.IP "\-" 4
Manual enrollment of client certificate. Offline fingerprint check required!
.IP "\-" 4
Acquisition of CA certificate(s)
.SH "OPTIONS"
.SS Basic Startup Options
.B \-v, \-\-version
.RS 4
Display the version of ipsec scepclient.
.PP
.RE
.B \-h, \-\-help
.RS 4
Display usage of ipsec scepclient.
.RE
.SS General Options
.B \-u, \-\-url \fIurl\fP
.RS 4
Full HTTP URL of the SCEP server to be used for certificate enrollment and CA certificate acquisition.
.RE
.PP
.B \-+, \-\-optionsfrom \fIfilename\fP
.RS 4
Reads additional options from \fIfilename\fP.
.RE
.PP
.B \-f, \-\-force
.RS 4
Overwrite existing output file[s].
.RE
.PP
.B \-q, \-\-quiet
.RS 4
Do not write log output to stderr.
.RE
.SS Options for CA Certificate Acquisition
.B \-o, \-\-out cacert[=\fIfilename\fP]
.RS 4
Output file of acquired CA certificate. If more then one CA certificate is available, \fIfilename\fP is used as prefix for the resulting files.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
.RE
.SS Options For Certificate Enrollment
.B \-i, \-\-in \fItype\fP[=\fIfilename\fP]
.RS 4
Input file for certificate enrollment. This option can be specified multiple times to specify input files for every \fItype\fP.
Input files can bei either DER or PEM encoded.
.PP
Supported values for \fItype\fP:
.IP "\fBpkcs1\fP" 12
RSA private key in PKCS#1 file format. If no input of this type is specified, a RSA key gets generated.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/private/myKey.der.
.IP "\fBcacert\-enc\fP" 12
CA certificate to encrypt the SCEP request. Has to be specified for certificate enrollment.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
.IP "\fBcacert\-sig\fP" 12
CA certificate to check signature of SCEP reply. Has to be specified for certificate enrollment.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/cacerts/caCert.der.
.RE
.PP
.B \-k, \-\-keylength \fIbits\fP
.RS 4
sets the key length for RSA key generation. The default length for a generated rsa key is set to 2048 bit.
.RE
.PP
.B \-D, \-\-days \fIdays\fP
.RS 4
Validity of the self-signed X.509 certificate in days. The default is 1825 days (5 years).
.RE
.PP
.B \-S, \-\-startdate \fIYYMMDDHHMMSS\fPZ
.RS 4
defines the \fBnotBefore\fP date when the X.509 certificate becomes valid.
The date has the format \fIYYMMDDHHMMSS\fP and must be specified in UTC (Zulu time).
If the \fB--startdate\fP option is not specified then the current date is taken as a default.
.RE
.PP
.B \-E, \-\-enddate \fIYYMMDDHHMMSS\fPZ
.RS 4
defines the \fBnotAfter\fP date when the X.509 certificate will expire.
The date has the format \fIYYMMDDHHMMSS\fP and must be specified in UTC (Zulu time).
If the \fB--enddate\fP option is not specified then the default \fBnotAfter\fP value is computed by
adding the validity interval specified by the \fB--days\fP option to the \fBnotBefore\fP date.
.RE
.PP
.B \-d, \-\-dn \fIdn\fP
.RS 4
Distinguished name as comma separated list of relative distinguished names. Use quotation marks for a distinguished name containing spaces. If the \fB\-\-dn\fP parameter is missing then the default "C=CH, O=Linux strongSwan, CN=\fIhostname\fP"
is used with \fIhostname\fP being the return value of the \fIgethostname\fP() function.
.RE
.PP
.B \-s, \-\-subjectAltName \fItype\fP=\fIvalue\fP
.RS 4
Include subjectAltName in certificate request. This option can be specified multiple times to specify a subjectAltName
for every \fItype\fP.
.PP
Supported values for \fItype\fP:
.IP "\fBemail\fP" 12
subjectAltName is a email address.
.IP "\fBdns\fP" 12
subjectAltName is a hostname.
.IP "\fBip\fP" 12
subjectAltName is a IP address.
.RE
.PP
.B \-p, \-\-password \fIpw\fP
.RS 4
Password to be included as a \fIchallenge password\fP in SCEP request.
If \fIpw\fP is \fB%prompt\fP', the password gets prompted for on the command line.
.IP
\- In automatic mode, this password corresponds to the preshared secret for the given enrollment.
.IP
\- In manual mode, this password can be used to later revoke the corresponding certificate.
.RE
.PP
.B \-a, \-\-algorithm \fIalgo\fP
.RS 4
Change symmetric algorithm to use for encryption of certificate Request.
The default is \fB3des\-cbc\fP.
.PP
Supported values for \fIalgo\fP:
.IP "\fBdes\-cbc\fP" 12
DES CBC encryption (key size = 56 bit).
.IP "\fB3des\-cbc\fP" 12
Triple DES CBC encryption (key size = 168 bit).
.RE
.PP
.B \-o, \-\-out \fItype\fP[=\fIfilename\fP]
.RS 4
Output file for certificate enrollment. This option can be specified multiple times to specify output files for every \fItype\fP.
.PP
Supported values for \fItype\fP:
.IP "\fBpkcs1\fP" 12
RSA private key in PKCS#1 file format. If specified, the RSA key used for enrollment is stored in file \fIfilename\fP.
If none of the \fItypes\fP listed below are specified, \fBscepclient\fP will stop after outputting this file.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/private/myKey.der.
.IP "\fBpkcs10\fP" 12
PKCS#10 certificate request. If specified, the PKCS#10 request used or certificate enrollment is stored in file \fIfilename\fP.
If none of the \fItypes\fP listed below are specified, \fBscepclient\fP will stop after outputting this file.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/req/myReq.der.
.IP "\fBpkcs7\fP" 12
PKCS#7 SCEP request as it is sent using HTTP to the SCEP server. If specified, this SCEP request is stored in file \fIfilename\fP.
If none of \fItypes\fP listed below is not specified, \fBscepclient\fP will stop after outputting this file.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/req/pkcs7.der.
.IP "\fBcert-self\fP" 12
Self-signed certificate. If specified the self-signed certificate is stored in file \fIfilename\fP.
.br
The default \fIfilename\fP is $CONFDIR/ipsec.d/certs/selfCert.der.
.IP "\fBcert\fP" 12
Enrolled certificate. This \fItype\fP must be specified for certificate enrollment.
The enrolled certificate is stored in file \fIfilename\fP.
.br
The default \fIfilename\fP is set to $CONFDIR/ipsec.d/certs/myCert.der.
.RE
.PP
.B \-m, \-\-method \fImethod\fP
.RS 4
Change HTTP request method for certificate enrollment. Default is \fBget\fP.
.PP
Supported values for \fImethod\fP:
.IP "\fBpost\fP" 12
Certificate enrollment using HTTP POST. Must be supported by the given SCEP server.
.IP "\fBget\fP" 12
Certificate enrollment using HTTP GET.
.RE
.PP
.B \-t, \-\-interval \fIseconds\fP
.RS 4
Set interval time in seconds when polling in manual mode.
The default interval is set to 5 seconds.
.RE
.PP
.B \-x, \-\-maxpolltime \fIseconds\fP
.RS 4
Set max time in seconds to poll in manual mode.
The default max time is set to unlimited.
.RE
.SS Debugging Output Options:
.B \-A, \-\-debug\-all
.RS 4
Log everything except private data.
.RE
.PP
.B \-P, \-\-debug\-parsing
.RS 4
Log parsing relevant stuff.
.RE
.PP
.B \-R, \-\-debug\-raw
.RS 4
Log raw hex dumps.
.RE
.PP
.B \-C, \-\-debug\-control
.RS 4
Log informations about control flow.
.RE
.PP
.B \-M, \-\-debug\-controlmore
.RS 4
Log more detailed informations about control flow.
.RE
.PP
.B \-X, \-\-debug\-private
.RS 4
Log sensitive data (e.g. private keys).
.RE
.SH "EXAMPLES"
.B ipsec scepclient \-\-out caCert \-\-url http://scepserver/cgi\-bin/pkiclient.exe \-f
.RS 4
Acquire CA certificate from SCEP server and store it in the default file $CONFDIR/ipsec.d/cacerts/caCert.der.
If more then one CA certificate is returned, store them in files named caCert.der\-1', caCert.der\-2', etc.
.br
Existing files are overwritten.
.RE
.PP
.B ipsec scepclient \-\-out pkcs1=joeKey.der \-k 1024
.RS 4
Generate RSA private key with key length of 1024 bit and store it in file joeKey.der.
.RE
.PP
.B ipsec scepclient \-\-in pkcs1=joeKey.der \-\-out pkcs10=joeReq.der \e
.br
.B \-\-dn \*(rqC=AT, CN=John Doe\*(rq \-s [email protected] \-p mypassword
.RS 4
Generate a PKCS#10 request and store it in file joeReq.der. Use the RSA private key joeKey.der
created earlier to sign the PKCS#10\-Request. In addition to the distinguished name include a
email\-subjectAltName and a challenge password in the request.
.RE
.PP
.B ipsec scepclient \-\-out pkcs1=joeKey.der \-\-out cert==joeCert.der \e
.br
.B \-\-dn \*(rqC=CH, CN=John Doe\*(rq \-k 512 \-p 5xH2pnT7wq \e
.br
.B \-\-url http://scep.hsr.ch/cgi\-bin/pkiclient.exe \e
.br
.B \-\-in cacert\-enc=caCert.der \-\-in cacert\-sig=caCert.der
.RS 4
Generate a new RSA key for the request and store it in joeKey.der. Then enroll a certificate and store as joeCert.der.
The challenge password is '5xH2pnT7wq'. The encryption and signature check has to be made with the same CA certificate
caCert.der.
.RE
.SH "BUGS"
\fB\-\-optionsfrom\fP seems to have parsing problems reading option files containing strings in quotation marks.
.SH "COPYRIGHT"
Copyright (C) 2005 Jan Hutter, Martin Willi
.br
Hochschule fuer Technik Rapperswil
.PP
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
.PP
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
File diff suppressed because it is too large Load Diff