123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461 |
- """
- StoneVPN - Easy OpenVPN certificate and configuration management
- (C) 2009-2012 by L.S. Keijser, <keijser@stone-it.com>
- 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.
- 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.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- """
- import commands
- import cStringIO
- import fileinput
- import getpass
- import glob
- import operator
- import os
- import random
- import re
- import shutil
- import smtplib
- import string
- import sys
- import time
- import zipfile
- from OpenSSL import SSL, crypto
- from optparse import OptionParser, OptionGroup
- from configobj import ConfigObj
- from time import strftime
- from datetime import date, datetime, timedelta
- from IPy import IP
- from string import atoi
- from datetime import datetime
- from email.MIMEMultipart import MIMEMultipart
- from email.MIMEBase import MIMEBase
- from email.MIMEText import MIMEText
- from email.Utils import formatdate
- from email import Encoders
- from socket import gethostname
- from StoneVPN import STONEVPN_VERSION
- def main():
- stonevpnconf = '/etc/stonevpn.conf'
- stonevpnver = STONEVPN_VERSION
-
- if os.path.exists(stonevpnconf):
- config = ConfigObj(stonevpnconf)
- sectionname = 'stonevpn conf'
- section=config[sectionname]
- crlfile = section['crlfile']
- prefix = section['prefix']
- pushrouter = section['pushrouter']
- cacertfile = section['cacertfile']
- cakeyfile = section['cakeyfile']
- openvpnconf = section['openvpnconf']
- ccddir = section['ccddir']
- working = section['working']
- opensslconf = section['opensslconf']
- ciphermethod = section['cipher']
- mail_server = section['mail_server']
- mail_cc = section['mail_cc']
- mail_msg = section['mail_msg']
- mail_from = section['mail_from']
- try:
- mail_passtxt = section['mail_passtxt']
- except:
- print "Missing variable 'mail_passtxt' in %s! Please update your configuration.\nHint: look at the example configuration file." % stonevpnconf
- sys.exit()
- else:
- print "File " + stonevpnconf + " does not exist!"
- sys.exit()
-
- if os.path.exists(opensslconf):
- config = ConfigObj(opensslconf)
- sectionname = 'CA_default'
- section=config[sectionname]
- defaultDays = section['default_days']
- else:
- print "Error: OpenSSL configuration file not found at %s" % opensslconf
- sys.exit()
-
- TYPE_RSA = crypto.TYPE_RSA
- TYPE_DSA = crypto.TYPE_DSA
- FILETYPE = crypto.FILETYPE_PEM
-
- parser = OptionParser(usage="%prog -f <filename> -n <commonname> [ OPTIONS ]",version="%prog " + stonevpnver)
-
- group_crl = OptionGroup(parser, "Certificate revocation options")
- group_general = OptionGroup(parser, "General options",
- "All general options are mandatory")
- group_extra = OptionGroup(parser, "Extra options",
- "To be used in conjunction with the general options.")
- group_info = OptionGroup(parser, "Information/printing options")
- group_ca = OptionGroup(parser, "CA certificate options")
- group_test = OptionGroup(parser, "Test/experimental options",
- "Caution: use these options with care.")
-
- def optional_arg(arg_default):
- def check_value(option,opt_str,value,parser):
-
- if parser.rargs and not parser.rargs[0].startswith('-'):
- val=parser.rargs[0]
- parser.rargs.pop(0)
- else:
-
- val=arg_default
-
- setattr(parser.values,option.dest,val)
- return check_value
-
- parser.add_option("-D", "--debug",
- action="count",
- dest="debug",
- help="enable debugging output")
- group_general.add_option("-n", "--name",
- action="store",
- type="string",
- dest="cname",
- help="Common Name, use quotes eg.: \"CNAME\" and only alphanumeric characters")
- group_general.add_option("-f", "--file",
- dest="fname",
- help="write to file FNAME (no extension!)")
- group_general.add_option("-o", "--config",
- action="store",
- dest="confs",
- default="windows",
- help="create config files for [windows|unix|mac|android|all]")
- group_extra.add_option("-e", "--prefix",
- action="store",
- dest="fprefix",
- default=prefix,
- help="prefix (almost all) generated files. Default = " + str(prefix))
- group_extra.add_option("-z", "--zip",
- action="store_true",
- dest="zip",
- help="add all generated files to a ZIP-file")
- group_extra.add_option("-m", "--mail",
- action="store",
- type="string",
- dest="emailaddress",
- help="send all generated files to EMAILADDRESS")
- group_extra.add_option("-i", "--free-ip",
- action="store_true",
- dest="freeip",
- help="locate and assign free ip")
- group_extra.add_option("-E", "--extrafile",
- action="append",
- dest="extrafile",
- help="include extra file(s) like documentation. Can be used multiple times")
- group_extra.add_option("-p", "--passphrase",
- action="callback",
- callback=optional_arg('please_prompt_me'),
- dest="passphrase",
- help="prompt for a passphrase when generating private key, or supply one on the commandline")
- group_extra.add_option("-M", "--mailpass",
- action="store_true",
- dest="mailpass",
- help="include passphrase in e-mail body (only useful with the '-m' option)")
- group_extra.add_option("-R", "--randpass",
- action="store",
- type="string",
- dest="randpass",
- help="generate a random password of RANDPASS characters (eg.: -R 8)")
- group_extra.add_option("-S", "--serverip",
- action="store",
- type="string",
- dest="server_ip",
- help="use this IP address for the server when generating the configuration file, overriding the one specified in stonevpn.conf")
- group_crl.add_option("-r", "--revoke",
- action="store",
- dest="serial",
- help="revoke certificate with serial SERIAL")
- group_extra.add_option("-u", "--route",
- action="append",
- dest="route",
- help="push extra route(s) to client. Specify multiple routes as: -u 192.168.1.1/32 -u 10.1.4.0/24")
- group_crl.add_option("-l", "--listrevoked",
- action="store_true",
- dest="listrevoked",
- help="list revoked certificates")
- group_crl.add_option("-C", "--crl",
- action="store_true",
- dest="displaycrl",
- help="display CRL file contents")
- group_info.add_option("-a", "--listall",
- action="store_true",
- dest="listall",
- help="list all certificates")
- group_info.add_option("--listcsv",
- action="store_true",
- dest="listallcsv",
- help="list all certificates (output as CSV)")
- group_info.add_option("-s", "--showserial",
- action="store_true",
- dest="showserial",
- help="display current SSL serial number")
- group_info.add_option("-c", "--printcert",
- action="store",
- dest="printcert",
- help="prints information about a certficiate file")
- group_info.add_option("-d", "--printindex",
- action="store_true",
- dest="printindex",
- help="prints index file")
- group_extra.add_option("-x", "--expire",
- action="store",
- dest="expiredate",
- help="certificate expires in EXPIREDATE h(ours), d(ays) or y(ears). The default is " + str(defaultDays) + " days. Example usage: -x 2h")
- group_crl.add_option("-N", "--newcrl",
- action="store_true",
- dest="emptycrl",
- help="create an empty CRL file (or overwrite an existing one)")
- group_ca.add_option("-A", "--newca",
- action="store",
- dest="newca",
- help="create a new self-signed CA certificate that's valid for NEWCA years")
- group_test.add_option("-t", "--test",
- action="store_true",
- dest="test",
- help="Danger, Will Robinson, Danger! test parameter - can do anything! Review source before executing!")
-
- parser.add_option_group(group_general)
- parser.add_option_group(group_extra)
- parser.add_option_group(group_info)
- parser.add_option_group(group_crl)
- parser.add_option_group(group_ca)
- parser.add_option_group(group_test)
-
- (options, args) = parser.parse_args()
- s = StoneVPN()
-
- s.debug = options.debug
- s.cname = options.cname
- s.fname = options.fname
- s.confs = options.confs
- s.fprefix = options.fprefix
- s.zip = options.zip
- s.emailaddress = options.emailaddress
- s.freeip = options.freeip
- s.passphrase = options.passphrase
- s.mailpass = options.mailpass
- s.randpass = options.randpass
- s.extrafile = options.extrafile
- s.server_ip = options.server_ip
- s.serial = options.serial
- s.route = options.route
- s.listrevoked = options.listrevoked
- s.displaycrl = options.displaycrl
- s.listall = options.listall
- s.listallcsv = options.listallcsv
- s.showserial = options.showserial
- s.printcert = options.printcert
- s.printindex = options.printindex
- s.expiredate = options.expiredate
- s.emptycrl = options.emptycrl
- s.newca = options.newca
- s.test = options.test
-
- s.cacertfile = cacertfile
- s.cakeyfile = cakeyfile
- s.openvpnconf = openvpnconf
- s.ccddir = ccddir
- s.working = working
- s.opensslconf = opensslconf
- s.pushrouter = pushrouter
- s.ciphermethod = ciphermethod
- s.prefix = prefix
- s.crlfile = crlfile
- s.mail_server = mail_server
- s.mail_cc = mail_cc
- s.mail_msg = mail_msg
- s.mail_from = mail_from
- s.mail_passtxt = mail_passtxt
- s.stonevpnconf = stonevpnconf
-
- s.TYPE_RSA = TYPE_RSA
- s.TYPE_DSA = TYPE_DSA
- s.FILETYPE = FILETYPE
- s.stonevpnver = stonevpnver
-
- if len(sys.argv[1:]) == 0:
- parser.print_help()
-
- if options.fname is None and options.serial is not None and options.listrevoked is not None and options.listall is not None and options.listallcsv is not None and options.showserial is not None and options.printcert is not None and options.printindex is not None and options.emptycrl is not None and options.test is not None and options.newca is not None:
- parser.error("Error: you have to specify a filename (FNAME)")
- else:
-
- myId = commands.getstatusoutput('id -u')[1]
- if not myId == '0':
- print "Sorry, root privileges required for this action."
- sys.exit(0)
- else:
- s.run()
- class StoneVPN:
- def __init__(self):
- """
- Constructor. Arguments will be filled in by optparse..
- """
- self.cname = None
- self.fname = None
- self.confs = None
- self.fprefix = None
- self.zip = None
- self.emailaddress = None
- self.freeip = None
- self.passphrase = None
- self.mailpass = None
- self.randpass = None
- self.extrafile = None
- self.server_ip = None
- self.serial = None
- self.route = None
- self.listrevoked = None
- self.displaycrl = None
- self.listall = None
- self.listallcsv = None
- self.showserial = None
- self.printcert = None
- self.printindex = None
- self.expiredate = None
- self.emptycrl = None
- self.newca = None
- self.test = None
-
- def readOpenSSLConf(self):
- if self.debug: print "DEBUG: parsing OpenSSL configuration file %s" % self.opensslconf
- config = ConfigObj(self.opensslconf)
- sectionname = 'req_distinguished_name'
- section=config[sectionname]
-
- global countryName, stateOrProvinceName, localityName, organizationName, organizationalUnitName, defaultDays, prefixdir, indexdb, serialfile, default_bits, default_md
-
- try:
- countryName = section['countryName_default']
- if len(countryName) is 0:
- print "Error: countryName_default is empty. Please edit %s first." % self.opensslconf
- sys.exit()
- except KeyError:
- print "Error: missing section 'countryName_default' in " + self.opensslconf
- sys.exit()
- try:
- stateOrProvinceName = section['stateOrProvinceName_default']
- if len(stateOrProvinceName) is 0:
- print "Error: stateOrProvinceName_default is empty. Please edit %s first." % self.opensslconf
- sys.exit()
- except KeyError:
- print "Error: missing section 'stateOrProvinceName_default' in " + self.opensslconf
- sys.exit()
- try:
- localityName = section['localityName_default']
- if len(localityName) is 0:
- print "Error: localityName_default is empty. Please edit %s first." % self.opensslconf
- sys.exit()
- except KeyError:
- print "Error: missing section 'localityName_default' in " + self.opensslconf
- sys.exit()
- try:
- organizationName = section['0.organizationName_default']
- if len(organizationName) is 0:
- print "Error: 0.organizationName_default is empty. Please edit %s first." % self.opensslconf
- sys.exit()
- except KeyError:
- print "Error: missing section '0.organizationName_default' in " + self.opensslconf
- sys.exit()
- try:
- organizationalUnitName = section['organizationalUnitName_default']
- if len(organizationalUnitName) is 0:
- print "Error: organizationalUnitName_default is empty. Please edit %s first." % self.opensslconf
- sys.exit()
- except KeyError:
- print "Error: missing section 'organizationalUnitName_default' in " + self.opensslconf
- sys.exit()
- sectionname = 'CA_default'
- section=config[sectionname]
- defaultDays = section['default_days']
- prefixdir = section['dir']
- indexdb = section['database'].replace('$dir', prefixdir)
- serialfile = section['serial'].replace('$dir', prefixdir)
- sectionname = 'req'
- section=config[sectionname]
- default_bits = section['default_bits']
- try:
- default_md = section['default_md']
- except KeyError:
- print "Warning: your OpenSSL configuration file misses key 'default_md'. Please add it. For now we'll assume SHA1'"
- default_md = 'sha1'
- def run(self):
- """
- StoneVPN's main function
- """
- if os.path.exists(self.opensslconf):
- self.readOpenSSLConf()
- else:
- print "File " + self.opensslconf + " does not exist!"
- sys.exit()
-
- if not os.path.exists(indexdb):
- print "Error: indexfile not found at: " + indexdb + " or insufficient rights."
- sys.exit()
-
- if not os.path.exists(serialfile):
- print "Error: serialfile not found at: " + serialfile + " or insufficient rights."
- sys.exit()
-
- if not self.fprefix == '':
- if not self.fprefix[-1] == '-':
- self.fprefix = str(self.fprefix) + '-'
-
- if not os.path.exists(self.working):
- print "Working dir didn't exist, making ..."
- os.mkdir(self.working)
-
- if self.cname:
- if self.fname is None:
- print "Error: required option -f/--file is missing."
- sys.exit()
- print "Creating " + self.fname + ".key and " + self.fname + ".crt for " + self.cname
- self.makeCert( self.fname, self.cname )
-
- if self.extrafile:
- if self.fname is None or self.cname is None:
- print "Error: required option -f/--file and/or -n/--name is missing."
- sys.exit()
- for efile in self.extrafile:
- if os.path.exists(efile):
-
- try:
- os.mkdir(self.working + '/' + self.fname + '-extrafiles')
- except:
- pass
- print "Adding extra file %s" % efile
- shutil.copy(efile, self.working + '/' + self.fname + '-extrafiles/')
- else:
-
- print "Error: file %s was not found."
- sys.exit()
-
-
- if self.zip:
- if self.fname is None or self.cname is None:
- print "Error: required option -f/--file and/or -n/--name is missing."
- sys.exit()
- print "Adding all files to " + self.working + "/" + self.fprefix + self.fname + ".zip"
- z = zipfile.ZipFile(self.working + "/" + self.fprefix + self.fname + ".zip", "w")
- for name in glob.glob(self.working + "/" + self.fprefix + self.fname + ".*"):
-
- if not name == self.working + "/" + self.fprefix + self.fname + ".zip":
- if self.debug: print "DEBUG: adding %s to %s" % (name.split('/')[-1],self.fprefix + self.fname + '.zip')
- z.write(name, os.path.basename(name), zipfile.ZIP_DEFLATED)
-
- z.write(self.cacertfile, os.path.basename(self.cacertfile), zipfile.ZIP_DEFLATED)
- z.write("/etc/openvpn/keys/ta.key", "ta.key", zipfile.ZIP_DEFLATED)
-
- if self.extrafile:
- for efile in self.extrafile:
- z.write(efile, os.path.basename(efile), zipfile.ZIP_DEFLATED)
-
- for file in glob.glob(self.working + "/" + self.fname + "-extrafiles/*"):
- os.remove(file)
-
- os.rmdir(self.working + "/" + self.fname + "-extrafiles")
- z.close()
-
- for file in glob.glob(self.working + "/" + self.fprefix + self.fname + ".*"):
- if not file == self.working + "/" + self.fprefix + self.fname + ".zip": os.remove(file)
-
-
- if self.freeip:
- if self.fname is None:
- print "Error: required option -f/--file is missing."
- sys.exit()
- print "Searching for free IP-address:"
-
- if not os.path.exists(self.openvpnconf):
- print "Error: OpenVPN server configuration file was not found at %s" % self.openvpnconf
- sys.exit()
-
- for line in fileinput.input(self.openvpnconf):
- if len(line.split()) > 0 and line.split()[0] == 'ifconfig-pool':
- pool_from = line.split()[1]
- pool_to = line.split()[2]
- print "Pool runs from " + pool_from + " to " + pool_to
-
-
-
-
- r = re.compile('(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})')
- mFrom = r.match(pool_from)
- mTo = r.match(pool_to)
- if self.debug:
- print "DEBUG: first 3 octets of ip_from are %s.%s.%s" % (mFrom.group(1),mFrom.group(2),mFrom.group(3))
- print "DEBUG: first 3 octets of ip_to are %s.%s.%s" % (mTo.group(1),mTo.group(2),mTo.group(3))
- from_3octs = str(mFrom.group(1)) + '.' + str(mFrom.group(2)) + '.' + str(mFrom.group(3))
- to_3octs = str(mTo.group(1)) + '.' + str(mTo.group(2)) + '.' + str(mTo.group(3))
- if from_3octs == to_3octs:
-
-
- if self.debug: print "DEBUG: both ip_from and ip_to are in the same subnet\nDEBUG: calculating range the 'easy' way.."
- range_4oct = range(int(mFrom.group(4)),int(mTo.group(4)))
-
- rangeIP = []
- for octet in range_4oct:
- rangeIP.append(from_3octs + "." + str(octet))
- else:
- rangeIP = []
-
-
- range_3oct = range(int(mFrom.group(3)),int(mTo.group(3)))
-
- range_3oct.append(int(mTo.group(3)))
- if self.debug: print "DEBUG: range_3oct is %s" % range_3oct
-
-
- for octet in range(int(mFrom.group(4)),255):
-
- rangeIP.append(from_3octs + "." + str(octet))
-
- if self.debug: print "DEBUG: remove %s from %s" % (mFrom.group(3),range_3oct)
- range_3oct.remove(int(mFrom.group(3)))
- if self.debug: print "DEBUG: range_3oct is now %s" % range_3oct
-
- for octet_3 in range_3oct:
- if int(octet_3) != int(mTo.group(3)):
- for octet in range(1,255):
- rangeIP.append(mFrom.group(1) + '.' + mFrom.group(2) + '.' + str(octet_3) + '.' + str(octet))
- else:
-
- for octet in range(1,int(mTo.group(4))):
- rangeIP.append(mFrom.group(1) + '.' + mFrom.group(2) + '.' + str(mTo.group(3)) + '.' + str(octet))
- if self.debug: print "DEBUG: rangeIP is %s" % rangeIP
-
- ipList = []
- for x in rangeIP:
- ipList.append(x)
-
- for file in glob.glob(self.ccddir+"/*"):
- if self.debug: print "DEBUG: parsing file: " + file
- for line in fileinput.input(file):
-
- if line.split()[0] == 'ifconfig-push':
-
- clientip = line.split()[2]
-
- if clientip in ipList:
- ipList.remove(clientip)
-
- servip = line.split()[1]
-
- if servip in ipList:
- ipList.remove(servip)
-
- ipList.sort()
-
-
- try:
- firstFree = ipList[0]
- except IndexError:
- print "Error: no free IP address left in pool!"
- sys.exit()
- try:
- secondFree = ipList[1]
- except IndexError:
- print "Error: no free IP address left in pool!"
- sys.exit()
- print "First free address: %s (local)" % firstFree
- print "Second free address: %s (peer)" % secondFree
-
- if not os.path.exists(self.ccddir):
- print "Client configuration directory didn't exist, making ..."
- os.mkdir(self.ccddir)
-
- nospaces_cname = self.cname.replace(' ', '_')
- f=open(self.ccddir + '/' + nospaces_cname, 'w')
- f.write('ifconfig-push ' + str(secondFree) + ' ' + str(firstFree) + '\n')
- f.write('push "route ' + self.pushrouter + ' 255.255.255.255"\n')
- f.close()
- print "CCD file written to: %s\nPlease review or make additional changes." % (self.ccddir + '/' + nospaces_cname)
- if self.listall:
- self.listAllCerts()
- if self.listallcsv:
- self.listAllCertsCSV()
- if self.displaycrl:
- self.displayCRL()
- if self.listrevoked:
- self.listRevokedCerts()
- if self.serial:
- self.revokeCert(str(self.serial))
- if self.showserial:
- print "Current SSL serial number (in hex): " + self.readSerial()
- if self.printindex:
- print "Current index file (" + indexdb + "):"
- self.printIndexDB()
- if self.printcert:
- self.print_cert ( self.printcert )
- if self.emailaddress:
- if self.fname is None or self.cname is None:
- print "Error: required option -f/--file and/or -n/--name is missing."
- sys.exit()
- mail_attachment = []
- mail_to = self.emailaddress
-
- if self.zip:
- mail_attachment.append(self.working + '/' + self.fprefix + self.fname + '.zip')
- self.send_mail(self.mail_from, mail_to, 'StoneVPN: generated files for ' + str(self.cname), self.mail_msg, mail_attachment)
- else:
-
- for name in glob.glob(self.working + "/" + self.fprefix + self.fname + ".*"):
- mail_attachment.append(name)
-
- mail_attachment.append(self.cacertfile)
-
- if self.extrafile:
- for efile in self.extrafile:
- mail_attachment.append(efile)
-
- self.send_mail(self.mail_from, mail_to, 'StoneVPN: generated files for ' + str(self.cname), self.mail_msg, mail_attachment)
- if self.route:
- if self.cname is None:
- print "Error: required option -n/--name is missing."
- sys.exit()
- IP.check_addr_prefixlen = False
- nospaces_cname = self.cname.replace(' ', '_')
- clientfile = self.ccddir + "/" + nospaces_cname
-
-
- nowwhat=0
- if not self.freeip:
- if os.path.exists(clientfile):
- overwrite=raw_input("Existing client configuration file was found. Do you want to (o)verwrite, (A)ppend or (s)kip): ")
- if overwrite in ('o', 'O'):
- os.remove(clientfile)
- nowwhat=2
- elif overwrite in ('s', 'S'):
- nowwhat=1
- if self.debug: print "DEBUG: adding %s routes" % len(self.route)
- for newroute in self.route:
- try:
- ip=IP(newroute)
- except ValueError:
- print "Error: invalid prefix length given."
- sys.exit()
- ip.NoPrefixForSingleIp = None
- ip.WantPrefixLen = 2
- if self.debug: print "DEBUG: ip: %s" % ip
-
- if IP(ip).version() != 4:
- print "Error: only IPv4 addresses are supported."
- sys.exit()
- route = str(ip).split('/')
- if self.debug:
- if len(route) == 1:
- print "DEBUG: only IP given, assume /32 netmask"
-
- if not os.path.exists(self.ccddir):
- print "Client configuration directory didn't exist, making ..."
- os.mkdir(self.ccddir)
- f=open(self.ccddir + '/' + nospaces_cname, 'a')
- if self.debug: print "DEBUG: route: %s" % route
- if nowwhat == 1:
- if self.debug: print "DEBUG: not writing route to client configfile!"
-
- if nowwhat != 1:
- print "Adding route %s / %s" % (route[0],route[1])
- f.write("push \"route " + route[0] + " " + route[1] + "\"\n")
- f.close()
- if nowwhat != 1:
- print "Wrote extra route(s) to " + self.ccddir + "/" + nospaces_cname
- if self.emptycrl:
- try:
- crl = crypto.CRL()
- except:
- print "\nError: CRL support is not available in your version of"
- print "pyOpenSSL. Please check the README file that came with"
- print "StoneVPN to see what you can do about this. For now, "
- print "you will have to revoke certificates manually.\n"
- sys.exit()
- if os.path.exists(self.crlfile):
- overwrite=raw_input("Existing crlfile was found. Do you want to overwrite (y/N): ")
- if overwrite not in ('y', 'Y'):
- print "Doing nothing.."
- sys.exit()
- print "Creating empty CRL file at %s" % self.crlfile
- cacert = self.load_cert(self.cacertfile)
- cakey = self.load_key(self.cakeyfile)
- newCRL = crl.export(cacert, cakey, days=90)
- f=open(self.crlfile, 'w')
- f.write(newCRL)
- f.close()
- if self.newca:
- self.createSelfSignedCertificate(self.newca)
- if self.test:
- print "Testing 1, 2, 5 ... three Sir!"
- sys.exit()
-
- def createKeyPair(self, type, bits):
- pkey = crypto.PKey()
- pkey.generate_key(type, bits)
- return pkey
-
- def createCertRequest(self, pkey, digest='sha256', **name):
- req = crypto.X509Req()
- subj = req.get_subject()
- for (key,value) in name.items():
- setattr(subj, key, value)
- req.set_pubkey(pkey)
- req.sign(pkey, default_md)
- return req
-
- def dec2hex(self, n):
- return "%X" % n
- def hex2dec(self, s):
- return int(s, 16)
- def printIndexDB(self):
- f=open(indexdb, 'r')
- for line in f:
- print line
- f.close()
- def readSerial(self):
- f=open(serialfile, 'r')
- serial = f.readline()
- f.close()
-
- if not serial.strip():
- serial = "0"
- return serial
- def writeSerial(self, serial):
- f=open(serialfile, 'w')
- f.write(serial)
- f.close()
- def writeIndex(self, index):
- f=open(indexdb, 'a')
- f.write(index)
- f.close()
-
- def createCertificate(self, req, (issuerCert, issuerKey), serial, (notBefore, notAfter), digest='sha256'):
- extensions = []
-
- extensions.append(crypto.X509Extension('basicConstraints',1, 'CA:FALSE'))
- try:
- extensions.append(crypto.X509Extension('nsComment',0, 'Created with stonevpn ' + str(self.stonevpnver)))
- except ValueError:
- print "\n=================================================================="
- print "Warning: your version of pyOpenSSL doesn't support X509Extensions."
- print "Please consult the README file that came with StoneVPN in order to"
- print "fix this. This is not trivial. The certificate will be generated."
- print "==================================================================\n"
-
- cert = crypto.X509()
- cert.set_version ( 2 )
-
- cert.add_extensions(extensions)
-
- goodserial = atoi(str(serial), 16)
- cert.set_serial_number(goodserial)
- if self.debug: print "DEBUG: notBefore is %s, notAfter is %s" % (notBefore,notAfter)
-
-
- now = datetime.utcnow().strftime("%Y%m%d%H%M%SZ")
- if self.debug: print "DEBUG: days is %s" % timedelta(seconds=notAfter)
- expire = (datetime.utcnow() + timedelta(seconds=notAfter)).strftime("%Y%m%d%H%M%SZ")
- cert.set_notBefore(now)
- cert.set_notAfter(expire)
- cert.set_issuer(issuerCert.get_subject())
- cert.set_subject(req.get_subject())
- cert.set_pubkey(req.get_pubkey())
- cert.sign(issuerKey, digest)
- return cert
-
- def getPass(self):
- passA = getpass.getpass('Enter passphrase for private key: ')
- passB = getpass.getpass('Enter passphrase for private key (again): ')
- if passA == passB:
- return passB
- else:
- print "Error: passwords don't match!"
- return "password_error"
-
-
- def save_key (self, fn, key):
- global keyPass
-
-
- if self.randpass:
- if self.debug: print "DEBUG: generating a random passphrase of %s characters" % self.randpass
- keyPass = ""
- for i in range(int(self.randpass)):
- keyPass += random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
- fp = open ( fn, 'w' )
- fp.write ( crypto.dump_privatekey ( self.FILETYPE, key, self.ciphermethod, keyPass ) )
- print "Private key encrypted with RANDOM passphrase: '%s'" % keyPass
- elif self.passphrase:
- if self.passphrase == 'please_prompt_me':
- keyPass = self.getPass()
- if keyPass is "password_error":
-
- sys.exit()
- else:
- fp = open ( fn, 'w' )
- fp.write ( crypto.dump_privatekey ( self.FILETYPE, key, self.ciphermethod, keyPass ) )
- if self.debug: print "DEBUG: private key encrypted with passphrase: '%s'" % keyPass
- else:
- fp = open ( fn, 'w' )
- fp.write ( crypto.dump_privatekey ( self.FILETYPE, key, self.ciphermethod, self.passphrase ) )
- if self.debug: print "DEBUG: private key encrypted with passphrase: '%s'" % self.passphrase
- else:
- fp = open ( fn, 'w' )
- fp.write ( crypto.dump_privatekey ( self.FILETYPE, key ) )
- fp.close ()
-
- def save_cert (self, fn, cert):
- fp = open ( fn, 'w' )
- fp.write ( crypto.dump_certificate ( self.FILETYPE, cert ) )
- fp.close ()
-
- def load_key (self, fn):
- fp = open ( fn, 'r' )
- ret = crypto.load_privatekey ( self.FILETYPE, fp.read() )
- fp.close ()
- return ret
-
- def load_cert (self, fn):
- fp = open ( fn, 'r' )
- ret = crypto.load_certificate ( self.FILETYPE, fp.read() )
- fp.close ()
- return ret
-
- def print_cert (self, cert):
- try:
- certfile = self.load_cert( cert )
- except:
- print "Error opening certificate file"
- sys.exit()
-
- certIssuerArray = str(certfile.get_issuer()).replace('<X509Name object \'', '').replace('\'>','').split('/')
- certIssuer = certIssuerArray[1] + ', ' + certIssuerArray[2] + ', ' + certIssuerArray[3] + ', ' + certIssuerArray[4]
- print "Issuer:\t\t" + str(certIssuer)
- certSubjectArray = str(certfile.get_subject()).replace('<X509Name object \'', '').replace('\'>','').split('/')
- certSubject = certSubjectArray[1] + ', ' + certSubjectArray[2] + ', ' + certSubjectArray[3] + ', ' + certSubjectArray[4]
- print "Subject:\t" + str(certSubject)
- print "Version:\t" + str(certfile.get_version())
- print "Serial number:\t" + str(certfile.get_serial_number())
- validFromYear = str(certfile.get_notBefore())[:4]
- validFromMonth = str(certfile.get_notBefore())[4:6]
- validFromDay = str(certfile.get_notBefore())[6:8]
- validFromTime = str(certfile.get_notBefore())[8:10] + ':' + str(certfile.get_notBefore())[10:12] + ':' + str(certfile.get_notBefore())[12:14]
- print "Valid from:\t" + validFromYear + '-' + validFromMonth + '-' + validFromDay + ' ' + validFromTime
- validUntilYear = str(certfile.get_notAfter())[:4]
- validUntilMonth = str(certfile.get_notAfter())[4:6]
- validUntilDay = str(certfile.get_notAfter())[6:8]
- validUntilTime = str(certfile.get_notAfter())[8:10] + ':' + str(certfile.get_notAfter())[10:12] + ':' + str(certfile.get_notAfter())[12:14]
- print "Valid until:\t" + validUntilYear + '-' + validUntilMonth + '-' + validUntilDay + ' ' + validUntilTime
- if str(certfile.has_expired()) == '1':
- print "Expired:\tyes"
- else:
- print "Expired:\tno"
- def createSelfSignedCertificate(self, years):
-
- if os.path.exists(self.cacertfile):
- print "Error: the CA certificate already exists at %s" % self.cacertfile
- sys.exit()
-
- if os.path.exists(self.cakeyfile):
-
- print "Warning: the CA keyfile already exists at %s, so we'll use it" % self.cakeyfile
- k = self.load_key(self.cakeyfile)
- else:
-
- k = crypto.PKey()
- k.generate_key(crypto.TYPE_RSA, int(default_bits))
- valid_until = (date.today() + timedelta(int(years)*365)).isoformat()
- print "Generating a self-signed CA certificate."
- print "The certificate is valid until %s." % valid_until
-
- cert = crypto.X509()
-
- cert.get_subject().C = countryName
- cert.get_subject().ST = stateOrProvinceName
- cert.get_subject().L = localityName
- cert.get_subject().O = organizationName
- cert.get_subject().OU = organizationalUnitName
- cert.get_subject().CN = gethostname()
- extensions = []
- extensions.append(crypto.X509Extension('basicConstraints',0, 'CA:TRUE'))
- cert.add_extensions(extensions)
- serial = self.hex2dec( self.readSerial() )
- cert.set_serial_number(serial)
- cert.gmtime_adj_notBefore(0)
- cert.gmtime_adj_notAfter(int(years)*365*24*60*60)
- cert.set_issuer(cert.get_subject())
- cert.set_pubkey(k)
- cert.sign(k, default_md)
-
- print "Writing CA private key to %s" % self.cakeyfile
- self.save_key (self.cakeyfile, k)
- print "Writing CA certificate to %s" % self.cacertfile
- self.save_cert (self.cacertfile, cert)
-
- def makeCert(self, fname, cname):
-
- for f in glob.glob(self.working + '/' + self.fprefix + fname + '.*'):
- if self.debug: print "DEBUG: removing old file %s" % f
- os.remove(f)
- pkey = self.createKeyPair(self.TYPE_RSA, int(default_bits))
- req = self.createCertRequest(pkey, CN=cname, C=countryName, ST=stateOrProvinceName, O=organizationName, OU=organizationalUnitName)
- try:
- cacert = self.load_cert( self.cacertfile )
- except:
- print "Error opening CA cert file"
- sys.exit()
- try:
- cakey = self.load_key(self.cakeyfile)
- except:
- print "Error opening CA key file"
- sys.exit()
-
-
-
- last = None
- for line in open(indexdb):
- last=line
- if last:
- last_serial = last.split("\t")[3].strip()
- else:
- last_serial = 0
- if self.debug: print "Last serial in indexdb: '%s'" % last_serial
- f=open(serialfile, 'r')
- serial = f.readline().strip()
- f.close()
- if self.debug: print "Next serial in serialfile: '%s'" % serial
- if serial == last_serial:
- print "Whoops! Last serial number in indexdb is the same as the next"
- print "one in serialfile: %s. This is probably caused by an older version" % serial
- print "of StoneVPN. We'll need to correct this (once) by increasing"
- newSerialDec = self.hex2dec(serial) + 1
- newSerial = self.dec2hex(newSerialDec)
- print "the value for next serial number to %s" % newSerial
- if len(newSerial) == 1:
- newSerial = '0' + str(newSerial)
- if self.debug: print "Now increasing %s by 1 to %s" % (serial,newSerial)
- f=open(serialfile, 'w')
- f.write(newSerial)
- f.close()
-
- curSerial = self.readSerial()
-
- timeNow = datetime.utcnow()
-
- timeNowIdx = datetime.now()
-
- newSerial = self.hex2dec(curSerial) + 1
- newSerialDec = newSerial
-
- newSerial = self.dec2hex(newSerial)
-
- if self.expiredate:
-
-
- expList = list(self.expiredate)
- try:
- unit = list(self.expiredate)[-1]
- if self.debug: print "DEBUG: time unit is %s" % unit
- except:
- print "Incorrect or missing time unit. Use h(ours), d(ays) or y(ears)."
- sys.exit()
- countRest = len(expList) - 1
- exp_time = ''.join(expList[0:countRest])
- if self.debug: print "DEBUG: exp_time is %s" % exp_time
- if unit not in ('h', 'H', 'd', 'D', 'y', 'Y'):
- print "Invalid time unit provided. Use h(ours), d(ays) or y(ears)."
- sys.exit()
- elif unit in ('h', 'H'):
- cert = self.createCertificate(req, (cacert, cakey), curSerial, (0, 60 * 60 * int(exp_time)))
- expDate = timeNow + timedelta(hours=int(exp_time))
- expDateIdx = timeNowIdx + timedelta(hours=int(exp_time))
- print "Certificate is valid for %s hour(s)." % exp_time
- elif unit in ('d', 'D'):
- cert = self.createCertificate(req, (cacert, cakey), curSerial, (0, 24 * 60 * 60 * int(exp_time)))
- expDate = timeNow + timedelta(days=int(exp_time))
- expDateIdx = timeNowIdx + timedelta(days=int(exp_time))
- print "Certificate is valid for %s day(s)." % exp_time
- elif unit in ('y', 'Y'):
- cert = self.createCertificate(req, (cacert, cakey), curSerial, (0, 24 * 60 * 60 * 365 * int(exp_time)))
- expDate = timeNow + timedelta(days=int(exp_time) * 365)
- expDateIdx = timeNowIdx + timedelta(days=int(exp_time) * 365)
- print "Certificate is valid for %s year(s)." % exp_time
- else:
- cert = self.createCertificate(req, (cacert, cakey), curSerial, (0, 24 * 60 * 60 * int(defaultDays)))
- expDate = timeNow + timedelta(days=int(defaultDays))
- expDateIdx = timeNowIdx + timedelta(days=int(defaultDays))
- print "Certificate is valid for %s day(s)." % defaultDays
- self.save_key ( self.working + '/' + self.fprefix + fname + '.key', pkey )
- self.save_cert ( self.working + '/' + self.fprefix + fname + '.crt', cert )
-
- if len(str(newSerial)) == 1:
- serialIdx = '0' + str(newSerial)
- else:
- serialIdx = newSerial
-
- self.writeSerial(serialIdx)
-
- shutil.copy(self.cacertfile, self.working)
-
- self.makeConfs(self.confs, fname)
-
- if self.debug: print "DEBUG: timeNow is %s" % timeNow
- if self.debug: print "DEBUG: expDate is %s" % expDate
-
- if len(str(curSerial)) == 1:
- serialNumber = '0' + str(curSerial)
- else:
- serialNumber = curSerial
-
- nospaces_cname = cname.replace(' ', '_')
-
- indexDate = expDateIdx.strftime("%y%m%d%H%M%S")
- if self.debug: print "DEBUG: indexDate is %s" % indexDate
-
- index = 'V\t' + str(indexDate) + 'Z\t\t' + str(serialNumber.strip()) + '\tunknown\t' + '/C=' + str(countryName) + '/ST=' + str(stateOrProvinceName) + '/O=' + str(organizationName) + '/OU=' + str(organizationalUnitName) + '/CN=' + str(nospaces_cname) + '/emailAddress=' + str(fname) + '@local\n'
- self.writeIndex(index)
-
- def makeConfs(self, sname, fname):
- config = ConfigObj(self.stonevpnconf)
-
- if sname == 'unix' or sname == 'linux':
- sectionname = 'unix conf'
- print "Generating UNIX configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.conf', 'w')
- elif sname == 'windows':
- sectionname = 'windows conf'
- print "Generating Windows configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.ovpn', 'w')
- elif sname == 'mac':
- sectionname = 'mac conf'
- print "Generating Mac configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.conf', 'w')
- elif sname == 'android':
- sectionname = 'android conf'
- print "Generating Android configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.ovpn', 'w')
- elif sname == 'all':
- print "Generating all configuration files"
- else:
- print "Incorrect OS type specified. Valid options are 'unix', 'windows', 'mac', 'android' or 'all'."
- sys.exit()
- if sname != 'all':
- section=config[sectionname]
-
- for var in section:
-
- if var == 'ca':
- cacertfilenopath = self.cacertfile.split('/')[int(len(self.cacertfile.split('/')) - 1)]
- f.write(section[var].replace('cacertfile', cacertfilenopath) + '\n')
- elif var == 'cert':
- f.write(section[var].replace('clientcertfile', self.fprefix + fname + '.crt') + '\n')
- elif var == 'key':
- f.write(section[var].replace('clientkeyfile', self.fprefix + fname + '.key') + '\n')
- elif var == 'ip':
- if self.server_ip:
- f.write("remote " + str(self.server_ip) + "\n")
- else:
- f.write(section[var] + '\n')
- else:
- f.write(section[var] + '\n')
- if sname == 'android':
- fp = open ( self.cacertfile, 'r' )
- f.write('\n' + "<ca>" + '\n' + fp.read() + "</ca>" + '\n')
- fp.close ()
- fp = open ( self.working + '/' + self.fprefix + fname + '.crt', 'r' )
- f.write('\n' + "<cert>" + '\n' + fp.read() + "</cert>" + '\n')
- fp.close ()
- fp = open ( self.working + '/' + self.fprefix + fname + '.key', 'r' )
- f.write('\n' + "<key>" + '\n' + fp.read() + "</key>" + '\n')
- fp.close ()
- f.close()
- else:
- os_versions = ["windows", "linux", "mac", "android"]
- for os_type in os_versions:
-
- if os_type == 'linux':
- sectionname = 'unix conf'
- print "Generating Linux configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.linux.conf', 'w')
- elif os_type == 'windows':
- sectionname = 'windows conf'
- print "Generating Windows configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.windows.ovpn', 'w')
- elif os_type == 'mac':
- sectionname = 'mac conf'
- print "Generating Mac configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.mac.conf', 'w')
- elif os_type == 'android':
- sectionname = 'android conf'
- print "Generating Android configuration file"
- f=open(self.working + '/' + self.fprefix + fname + '.android.ovpn', 'w')
- section=config[sectionname]
- for var in section:
- if var == 'ca':
- cacertfilenopath = self.cacertfile.split('/')[int(len(self.cacertfile.split('/')) - 1)]
- f.write(section[var].replace('cacertfile', cacertfilenopath) + '\n')
- elif var == 'cert':
- f.write(section[var].replace('clientcertfile', self.fprefix + fname + '.crt') + '\n')
- elif var == 'key':
- f.write(section[var].replace('clientkeyfile', self.fprefix + fname + '.key') + '\n')
- else:
- f.write(section[var] + '\n')
- if os_type == 'android':
- fp = open ( self.cacertfile, 'r' )
- f.write('\n' + "<ca>" + '\n' + fp.read() + "</ca>" + '\n')
- fp.close ()
- fp = open ( self.working + '/' + self.fprefix + fname + '.crt', 'r' )
- f.write('\n' + "<cert>" + '\n' + fp.read() + "</cert>" + '\n')
- fp.close ()
- fp = open ( self.working + '/' + self.fprefix + fname + '.key', 'r' )
- f.write('\n' + "<key>" + '\n' + fp.read() + "</key>" + '\n')
- fp.close ()
- f.close()
-
- def revokeCert(self, serial):
- if not os.path.exists(self.crlfile):
- print "Error: CRL file not found at: " + self.crlfile + " or insufficient rights."
- sys.exit()
- try:
- crl = crypto.CRL()
- except:
- print "\nError: CRL support is not available in your version of"
- print "pyOpenSSL. Please check the README file that came with"
- print "StoneVPN to see what you can do about this. For now, "
- print "you will have to revoke certificates manually.\n"
- sys.exit()
-
-
-
- t=open(self.working + '/index.tmp', 'w')
-
-
- print "Reading SSL database: " + indexdb
- input = open(indexdb, 'r')
- f=open(self.working + '/revoked.crl', 'w')
- crlTime = str(strftime("%y%m%d%H%M%S")) + 'Z'
- for line in input:
-
- if line.split()[0] == 'R':
-
-
- if line.split()[3] == serial.upper():
- print "Certificate with serial %s already revoked!" % serial.upper()
- os.remove(self.working + '/index.tmp')
- os.remove(self.working + '/revoked.crl')
- sys.exit()
- else:
- revSerial = str(line.split()[3])
- revDate = str(line.split()[2])
- revoked = crypto.Revoked()
- revoked.set_rev_date('20' + str(revDate))
- revoked.set_serial(revSerial)
-
-
- crl.add_revoked(revoked)
-
- print "Re-adding existing revoked certificate to CRL with date " + revDate + " and serial " + revSerial
- t.write(line)
- else:
-
-
- if line.split()[2] == serial.upper():
-
-
- if self.debug: print "DEBUG: found match for %s in index file" % serial.upper()
- newDN = '/'.join(line.split('/')[1:])
- revokedLine = 'R\t' + str(line.split()[1]) + '\t' + crlTime + '\t' + serial.upper() + '\tunknown\t' + str(newDN)
- t.write(revokedLine)
- else:
-
-
- t.write(line)
-
- print "Adding new revoked certificate to CRL with date " + crlTime + " and serial " + serial.upper()
- t.close()
- revoked = crypto.Revoked()
- now = datetime.utcnow().strftime("%Y%m%d%H%M%SZ")
- revoked.set_rev_date(now)
- revoked.set_serial(serial)
-
-
- crl.add_revoked(revoked)
- cacert = self.load_cert(self.cacertfile)
- cakey = self.load_key(self.cakeyfile)
- newCRL = crl.export(cacert, cakey, days=20)
- f.write(newCRL)
- f.close()
- shutil.move(indexdb,indexdb + '.old')
- shutil.move(self.working + '/index.tmp',indexdb)
- shutil.move(self.crlfile,self.crlfile + '.old')
- shutil.move(self.working + '/revoked.crl',self.crlfile)
- print "New CRL written to: %s. Backup created as: %s." % (self.crlfile,self.crlfile + '.old')
- print "New index written to: %s. Backup created as: %s." % (indexdb,indexdb + '.old')
- def displayCRL(self):
- if not os.path.exists(self.crlfile):
- print "Error: CRL file not found at %s" % self.crlfile
- print "You can create one with: stonevpn --newcrl"
- sys.exit()
- text = open(self.crlfile, 'r').read()
- print "Parsing CRL file %s" % self.crlfile
- try:
- crl = crypto.load_crl(crypto.FILETYPE_PEM, text)
- revs = crl.get_revoked()
- except:
- print "\nError: CRL support is not available in your version of"
- print "pyOpenSSL. Please check the README file that came with"
- print "StoneVPN to see what you can do about this. For now, "
- print "you will have to display the CRL file manually using:\n"
- print "$ openssl crl -in %s -noout -text\n" % self.crlfile
- sys.exit()
- if not revs is None:
- print "Total certificates revoked: %s\n" % len(revs)
- print "Serial\tRevoked at date"
- print "======\t========================"
- for revoked in revs:
- revSerial = revoked.get_serial()
- revDate = revoked.get_rev_date()[0:-1]
- revoDate = time.strptime(revDate, "%Y%m%d%H%M%S")
- print str(revSerial) + "\t" + time.strftime("%c", revoDate)
- else:
- print "No revoked certificates found."
- def listRevokedCerts(self):
-
-
- print "Reading SSL database: " + indexdb
- input = open(indexdb, 'r')
- revCerts = []
- print "Finding revoked certificates..."
- for line in input:
- if line.split()[0] == 'R':
- revCerts.append(line)
- count = 0
- while count < len(revCerts):
-
- print "Issued to:\t\t%s" % str(revCerts[count]).split('CN=')[1].split('/')[0]
- print "Status:\t\t\tRevoked"
- expDate = str(revCerts[count].split()[1])
- print "Expiry date:\t\t20%s-%s-%s %s:%s:%s" % (expDate[:2],expDate[2:4],expDate[4:6],expDate[6:8],expDate[8:10],expDate[10:12])
- revDate = str(revCerts[count].split()[2])
- print "Revocation date:\t20%s-%s-%s %s:%s:%s" % (revDate[:2],revDate[2:4],revDate[4:6],revDate[6:8],revDate[8:10],revDate[10:12])
- print "Serial:\t\t\t%s" % str(revCerts[count].split()[3])
- lineDN = line.split('unknown')[1].strip()
- newDN = ''.join(lineDN).replace('/',',')
- print "DN:\t\t\t%s" % newDN
- print "\n"
- count = count + 1
- def indent(self, rows, hasHeader=False, headerChar='-', delim=' | ', justify='left',
- separateRows=False, prefix='', postfix='', wrapfunc=lambda x:x):
-
- def rowWrapper(row):
- newRows = [wrapfunc(item).split('\n') for item in row]
- return [[substr or '' for substr in item] for item in map(None,*newRows)]
-
- logicalRows = [rowWrapper(row) for row in rows]
-
- columns = map(None,*reduce(operator.add,logicalRows))
-
- maxWidths = [max([len(str(item)) for item in column]) for column in columns]
- rowSeparator = headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + \
- len(delim)*(len(maxWidths)-1))
-
- justify = {'center':str.center, 'right':str.rjust, 'left':str.ljust}[justify.lower()]
- output=cStringIO.StringIO()
- if separateRows: print >> output, rowSeparator
- for physicalRows in logicalRows:
- for row in physicalRows:
- print >> output, \
- prefix \
- + delim.join([justify(str(item),width) for (item,width) in zip(row,maxWidths)]) \
- + postfix
- if separateRows or hasHeader: print >> output, rowSeparator; hasHeader=False
- return output.getvalue()
- def listAllCerts(self):
-
- input = open(indexdb, 'r')
- data = ''
- for line in input:
- if line.split()[0] == 'R':
- issuee = line.split('/')[-2:][0].replace('CN=','').replace('_',' ').replace(',','_')
- data = str(data) + str(line.split()[3]) + ',' + str(issuee)
- data = str(data) + ',' + "Revoked"
- revDate = str(line.split()[2]).replace('Z','')
- data = str(data) + ',' + '20' + revDate[:2] + '-' + revDate[2:4] + '-' + revDate[4:6] + ' ' + revDate[6:8] + ':' + revDate[8:10] + ':' + revDate[10:12] + '\n'
- else:
- issuee = line.split('/')[-2:-1][0].split('\t')[0].replace('CN=','').replace('_',' ').replace(',','_')
- data = str(data) + str(line.split()[2]) + ',' + str(issuee)
- expDate = str(line.split()[1]).replace('Z','')
- ed_long = "20" + str(expDate)
- expiredate = int(time.mktime(time.strptime(str(datetime(int(ed_long[:4]),int(ed_long[4:6]),int(ed_long[6:8]),int(ed_long[8:10]),int(ed_long[10:12]),int(ed_long[12:14]))),"%Y-%m-%d %H:%M:%S")))
- timenow = int(time.mktime(time.localtime()))
- if int(timenow) < int(expiredate):
- data = str(data) + ',Valid'
- else:
- data = str(data) + ',Expired'
- data = str(data) + ',' + '20' + expDate[:2] + '-' + expDate[2:4] + '-' + expDate[4:6] + ' ' + expDate[6:8] + ':' + expDate[8:10] + ':' + expDate[10:12] + '\n'
- rows = []
- rows.append(('Serial','Name','Status','Expiry date'))
- for row in data.splitlines():
- rows.append(row.strip().split(','))
- width = 60
- print self.indent(rows,hasHeader=True)
- def listAllCertsCSV(self):
-
-
- input = open(indexdb, 'r')
- for line in input:
- if line.split()[0] == 'R':
- issuee = line.split('/')[-2:][0].replace('CN=','').replace('_',' ').replace(',','_')
- sys.stdout.write(str(issuee) + ",")
- sys.stdout.write("Revoked,")
- revDate = str(line.split()[2]).replace('Z','')
- sys.stdout.write("20%s-%s-%s %s:%s:%s," % (revDate[:2],revDate[2:4],revDate[4:6],revDate[6:8],revDate[8:10],revDate[10:12]))
- sys.stdout.write(str(line.split()[3]) + ",")
- else:
- issuee = line.split('/')[-2:-1][0].split('\t')[0].replace('CN=','').replace('_',' ').replace(',','_')
- sys.stdout.write(str(issuee) + ",")
- expDate = str(line.split()[1]).replace('Z','')
- ed_long = "20" + str(expDate)
- expiredate = int(time.mktime(time.strptime(str(datetime(int(ed_long[:4]),int(ed_long[4:6]),int(ed_long[6:8]),int(ed_long[8:10]),int(ed_long[10:12]),int(ed_long[12:14]))),"%Y-%m-%d %H:%M:%S")))
- timenow = int(time.mktime(time.localtime()))
- if int(timenow) < int(expiredate):
- sys.stdout.write("Valid,")
- else:
- sys.stdout.write("Expired,")
- sys.stdout.write("20%s-%s-%s %s:%s:%s," % (expDate[:2],expDate[2:4],expDate[4:6],expDate[6:8],expDate[8:10],expDate[10:12]))
- sys.stdout.write(str(line.split()[2]) + ",")
- def send_mail(self, send_from, send_to, subject, text, attachment=[]):
- print "Generating e-mail"
- msg = MIMEMultipart()
- msg['From'] = send_from
- msg['To'] = send_to
- msg['CC'] = self.mail_cc
- msg['Date'] = formatdate(localtime=True)
- msg['Subject'] = subject
- text = text.replace('EMAILRECIPIENT', self.cname)
-
- if self.mailpass:
- if self.passphrase is None and self.randpass is None:
- print "Error: you need to specify either a passphrase or generate a random one."
- sys.exit()
- if keyPass:
- if self.debug: print "DEBUG: including password help text in email body"
- text = text.replace('PASSPHRASETXT', self.mail_passtxt)
-
- text = text.replace('OPENSSLPASS', keyPass)
- else:
- text = text.replace('PASSPHRASETXT', '')
- msg.attach( MIMEText(text, 'html') )
-
- if type(attachment) == 'string':
- part = MIMEBase('application', "octet-stream")
- part.set_payload( open(attachment,"rb").read() )
- Encoders.encode_base64(part)
- part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attachment))
- msg.attach(part)
- else:
- for f in attachment:
- print "Attaching file %s" % f
- part = MIMEBase('application', "octet-stream")
- part.set_payload( open(f,"rb").read() )
- Encoders.encode_base64(part)
- part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
- msg.attach(part)
-
- print 'Sending e-mail with attachment(s) to %s' % self.emailaddress
- smtp = smtplib.SMTP(self.mail_server)
- smtp.sendmail(send_from, send_to, msg.as_string())
- smtp.close()
|