Do not accept certificates that do not match our key.
[certmaster.git] / certmaster / certs.py
1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
5 #
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
10 #
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14 # Copyright (c) 2007 Red Hat, inc
15 #- Written by Seth Vidal skvidal @ fedoraproject.org
16
17 from OpenSSL import crypto
18 import socket
19 import os
20 import utils
21
22 def_country = 'UN'
23 def_state = 'FC'
24 def_local = 'Certmaster-town'
25 def_org = 'certmaster'
26 def_ou = 'slave-key'
27
28
29 def make_keypair(dest=None):
30 pkey = crypto.PKey()
31 pkey.generate_key(crypto.TYPE_RSA, 2048)
32 if dest:
33 destfd = os.open(dest, os.O_RDWR|os.O_CREAT, 0600)
34 os.write(destfd, (crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)))
35 os.close(destfd)
36
37 return pkey
38
39
40 def make_csr(pkey, dest=None, cn=None):
41 req = crypto.X509Req()
42 req.get_subject()
43 subj = req.get_subject()
44 subj.C = def_country
45 subj.ST = def_state
46 subj.L = def_local
47 subj.O = def_org
48 subj.OU = def_ou
49 if cn:
50 subj.CN = cn
51 else:
52 subj.CN = utils.get_hostname()
53 subj.emailAddress = 'root@%s' % subj.CN
54
55 req.set_pubkey(pkey)
56 req.sign(pkey, 'md5')
57 if dest:
58 destfd = os.open(dest, os.O_RDWR|os.O_CREAT, 0644)
59 os.write(destfd, crypto.dump_certificate_request(crypto.FILETYPE_PEM, req))
60 os.close(destfd)
61
62 return req
63
64
65 def retrieve_key_from_file(keyfile):
66 fo = open(keyfile, 'r')
67 buf = fo.read()
68 keypair = crypto.load_privatekey(crypto.FILETYPE_PEM, buf)
69 return keypair
70
71
72 def retrieve_csr_from_file(csrfile):
73 fo = open(csrfile, 'r')
74 buf = fo.read()
75 csrreq = crypto.load_certificate_request(crypto.FILETYPE_PEM, buf)
76 return csrreq
77
78
79 def retrieve_cert_from_file(certfile):
80 fo = open(certfile, 'r')
81 buf = fo.read()
82 cert = crypto.load_certificate(crypto.FILETYPE_PEM, buf)
83 return cert
84
85
86 def create_ca(CN="Certmaster Certificate Authority", ca_key_file=None, ca_cert_file=None):
87 cakey = make_keypair(dest=ca_key_file)
88 careq = make_csr(cakey, cn=CN)
89 cacert = crypto.X509()
90 cacert.set_serial_number(0)
91 cacert.gmtime_adj_notBefore(0)
92 cacert.gmtime_adj_notAfter(60*60*24*365*10) # 10 yrs - hard to beat this kind of cert!
93 cacert.set_issuer(careq.get_subject())
94 cacert.set_subject(careq.get_subject())
95 cacert.set_pubkey(careq.get_pubkey())
96 cacert.sign(cakey, 'md5')
97 if ca_cert_file:
98 destfo = open(ca_cert_file, 'w')
99 destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cacert))
100 destfo.close()
101
102
103 def _get_serial_number(cadir):
104 serial = '%s/serial.txt' % cadir
105 i = 1
106 if os.path.exists(serial):
107 f = open(serial, 'r').read()
108 f = f.replace('\n','')
109 try:
110 i = int(f)
111 i+=1
112 except ValueError, e:
113 i = 1
114
115 _set_serial_number(cadir, i)
116 return i
117
118
119 def _set_serial_number(cadir, last):
120 serial = '%s/serial.txt' % cadir
121 f = open(serial, 'w')
122 f.write(str(last) + '\n')
123 f.close()
124
125
126 def create_slave_certificate(csr, cakey, cacert, cadir, slave_cert_file=None):
127 cert = crypto.X509()
128 cert.set_serial_number(_get_serial_number(cadir))
129 cert.gmtime_adj_notBefore(0)
130 cert.gmtime_adj_notAfter(60*60*24*365*10) # 10 yrs - hard to beat this kind of cert!
131 cert.set_issuer(cacert.get_subject())
132 cert.set_subject(csr.get_subject())
133 cert.set_pubkey(csr.get_pubkey())
134 cert.sign(cakey, 'md5')
135 if slave_cert_file:
136 destfo = open(slave_cert_file, 'w')
137 destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
138 destfo.close()
139 return cert
140
141 def check_cert_key_match(cert, key):
142 if not isinstance(cert, crypto.X509Type):
143 cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
144 if not isinstance(key, crypto.PKeyType):
145 key = crypto.load_privatekey(crypto.FILETYPE_PEM, key)
146
147 from OpenSSL import SSL
148 context = SSL.Context(SSL.SSLv3_METHOD)
149 try:
150 context.use_certificate(cert)
151 context.use_privatekey(key)
152 return True
153 except:
154 return False