Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/certutil
blob: bac272700e13d9d99fac5287cf9e5be41ef28316 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#!/bin/sh
#ident $Id: certutil,v 2.2 2001/05/27 12:16:31 lukeh Exp $
#
# certutil -- manage trusted X.509 certificates
# inspired by Netscape PKCS #11 toolkit
# contributed by Jarkko Turkulainen <jt@wapit.com>
#
#
# INTRODUCTION
#
#    certutil can be used with various OpenSSL routines and tools
#    that utilize OpenSSL. Example:
#
#    $ openssl s_client -CApath certdir
#
#    where certdir is a directory created by certutil. Other well known
#    programs that use the same format are stunnel, sendmail and pam_ldap
#
#
#
# HOWTO
#
# 1. Initialize certificate database
#
#    Simply by adding a new certificate. If the certificate directory
#    doesn't exist, the script asks for creating a one. Example:
#
#    $ certutil -a -n "First Cert" -i cert.pem -d /home/jt/mycerts
#    ./certutil: cannot access /home/jt/mycerts, create? [y/N] y
#
#
# 2. Add new certificate
#
#    $ certutil -a -n "My Cert" -i cert.pem [-d certdir]
#
#    Note that nickname (-n) must exist. certdir is optional - if it's
#    not given, $PWD is used. The directory must have a file named certs.dat.
#    If that file doesn't exist, the script refuses to do anything. If your
#    certs.dat file is corrupted, "rm -rf" the whole dir and start from
#    the scratch. cert.pem is the actual sertificate.
#
# 3. Delete certificate
#
#    $ certutil -r -n "My Cert" [-d certdir]
#
#    This command removes the certificate named "My Cert". certdir is 
#    optional, see 2.
#
# 4. List sertificates
#
#    $ certutil -l [-d certdir]
#
#    And again, certdir is optional.
#
# 5. View certificate properties
#
#    $ certutil -v -n "My Cert" [-d certdir]
#
#


# Print usage
usage() {
	cat << EOF

Usage: $0 -l [-d dir]
          -a -n name -i file [-d dir]
          -r -n name [-d dir]
          -v -n name [-d dir]

       Commands:
          -l   -- List sertificates (requires a valid dir)
          -a   -- Add sertificate and create dir if necessary
          -r   -- Remove sertificate (requires a valid dir)
          -v   -- View sertificate (requires a valid dir)

       Parameters:
          dir  -- Certificate directory, or \$PWD if not given
          name -- Nickname of the certificate
          file -- Certificate file in PEM format

EOF
	exit 1
}

# Check path
check_path() {

	# check the directory
	if [ ! -d $CDIR -a $ADD -eq 1 ]; then
		echo -n "$0: cannot access $CDIR, create? [y/N] "
		read LINE
		case $LINE in
			y|Y)
				mkdir $CDIR
				chmod 700 $CDIR
				touch $CDIR/certs.dat
				chmod 600 $CDIR/certs.dat
				;;
			*)
				exit 1
				;;
		esac
	fi

	# check certs.dat
	if [ ! -e $CDIR/certs.dat ]; then
		echo "$0: please specify a valid cert directory"
		exit 1
	fi
}

# Add certificates
add_cert() {
	check_path
	if [ ! -e $FILE ]; then	
		echo "$0: cannot find $FILE"
		exit 1
	fi
	HASH=`openssl x509 -in $FILE -hash -noout 2>/dev/null`.0
	if [ $? -ne 0 ]; then
		echo "$0: unable to load certificate $FILE"
		exit 1
	fi

	if grep "^$CNAME|" $CDIR/certs.dat 1>/dev/null 2>&1; then
		echo "$0: nickname already in use"
		exit 1
	fi

	if [ -e $CDIR/$HASH ]; then
		echo "$0: certificate already in directory"
		echo `openssl x509 -in $CDIR/$HASH -subject -noout`
		exit 1
	else
		cp $FILE $CDIR/$HASH
		chmod 600 $CDIR/$HASH
		echo "$CNAME|$HASH" >> $CDIR/certs.dat
		chmod 600 $CDIR/certs.dat
	fi

}

# List certificates
#
# (this is too slow...)
#
list_cert() {
	check_path
	echo
	echo "Certificates in directory $CDIR"
	echo
	printf "%-30s%s\n" nickname subject/issuer
	echo "----------------------------------------------------------------------------"
	cat $CDIR/certs.dat | while read LINE; do
		NICK=`echo $LINE | cut -d "|" -f 1`
		HASH=`echo $LINE | cut -d "|" -f 2`
		SUBJECT=`openssl x509 -in $CDIR/$HASH -subject -noout`
		ISSUER=`openssl x509 -in $CDIR/$HASH -issuer -noout`
		printf "%-30s%s\n" "$NICK" "$SUBJECT"
		printf "%-30s%s\n\n" "" "$ISSUER"

	done
}

# Remove certificates
remove_cert() {
	check_path
	(
	cat $CDIR/certs.dat | while read LINE; do
		NICK=`echo $LINE | cut -d "|" -f 1`
		HASH=`echo $LINE | cut -d "|" -f 2`
		if [ "$CNAME" = "$NICK" ]; then
			rm $CDIR/$HASH
		else
			echo $LINE
		fi
	done
	) > /tmp/$$
	mv /tmp/$$ $CDIR/certs.dat
	chmod 600 $CDIR/certs.dat
}

# View certificate
view_cert() {
	check_path
	cat $CDIR/certs.dat | while read LINE; do
		NICK=`echo $LINE | cut -d "|" -f 1`
		HASH=`echo $LINE | cut -d "|" -f 2`
		if [ "$CNAME" = "$NICK" ]; then
			openssl x509 -in $CDIR/$HASH -text
			return 1
		fi
	done
}

# Parse option string
ADD=0
REMOVE=0
LIST=0
VIEW=0
while getopts "arlvd:n:i:" OPT; do
	case $OPT in
		a)
			ADD=1
			;;
		r)
			REMOVE=1
			;;
		l)
			LIST=1
			;;
		v)
			VIEW=1
			;;
		d)
			CDIR=$OPTARG
			;;
		n)
			CNAME=$OPTARG
			;;
		i)
			FILE=$OPTARG
			;;
		*)
			usage
			;;
	esac
done

# Default options
CDIR=${CDIR:=.}

# Check command line options
if [ $ADD -eq 1 -a $REMOVE -eq 0 -a $LIST -eq 0 -a $VIEW -eq 0 ]; then
	if [ -n "$CNAME" -a -n "$FILE" ]; then
		add_cert
	else
		echo "$0: missing certificate name or file"
		usage
	fi
elif [ $REMOVE -eq 1 -a $ADD -eq 0 -a $LIST -eq 0 -a $VIEW -eq 0 ]; then
	if [ -n "$CNAME" ]; then
		remove_cert
	else
		echo "$0: missing certificate name"
		usage
	fi
elif [ $LIST -eq 1 -a $ADD -eq 0 -a $REMOVE -eq 0 -a $VIEW -eq 0 ]; then
	list_cert
elif [ $VIEW -eq 1 -a $ADD -eq 0 -a $REMOVE -eq 0 -a $LIST -eq 0 ]; then
	if [ -n "$CNAME" ]; then
		if view_cert; then
			echo "$0: cert named \"$CNAME\" not found"
			exit 1
		fi
	else
		echo "$0: missing certificate name"
		usage
	fi
else
	usage
fi