scripts: Package signing tool verifies using certificate.

Package signing tool verifies signed data using certificate instead 
of public key. It also verifies certificate, warns if it's self 
signed, fails if it's invalid.
This commit is contained in:
Bahadır Kandemir
2010-10-25 10:50:43 +00:00
parent 66f8c6cb52
commit cf3a6f52bc
2 changed files with 79 additions and 14 deletions
-1
View File
@@ -5,7 +5,6 @@ mkdir certs
openssl genrsa -des3 -out certs/enc_key.pem 1024 openssl genrsa -des3 -out certs/enc_key.pem 1024
openssl req -new -subj '/C=TR/ST=Kocaeli/L=Gebze/CN=Pardus' -key certs/enc_key.pem -out certs/req.pem openssl req -new -subj '/C=TR/ST=Kocaeli/L=Gebze/CN=Pardus' -key certs/enc_key.pem -out certs/req.pem
openssl req -x509 -key certs/enc_key.pem -in certs/req.pem -out certs/cert.pem -days 365 openssl req -x509 -key certs/enc_key.pem -in certs/req.pem -out certs/cert.pem -days 365
openssl x509 -inform pem -in certs/cert.pem -pubkey -noout > certs/pub_key.pem
# Feel free to share 'certs/cert.pem' and 'certs/pub_key.pem' with anyone, keep others to yourself. # Feel free to share 'certs/cert.pem' and 'certs/pub_key.pem' with anyone, keep others to yourself.
+79 -13
View File
@@ -15,13 +15,18 @@ import sys
import tempfile import tempfile
import zipfile import zipfile
def sign_data(data, certificate, password_fd): # Certificate validity
VALID = 1
SELF_SIGNED = 0
INVALID = -1
def sign_data(data, key_file, password_fd):
""" """
Signs data with given certificate. Signs data with given certificate.
Arguments: Arguments:
data: Data to be signed data: Data to be signed
certificate: Private certificate key_file: Private key
password_fd: File that contains passphrase password_fd: File that contains passphrase
Returns: Returns:
Signed data Signed data
@@ -31,7 +36,7 @@ def sign_data(data, certificate, password_fd):
# Use OpenSSL to sign data # Use OpenSSL to sign data
command = '/usr/bin/openssl dgst -sha1 -sign %s -passin fd:%d' command = '/usr/bin/openssl dgst -sha1 -sign %s -passin fd:%d'
command = command % (certificate, password_fd.fileno()) command = command % (key_file, password_fd.fileno())
command = shlex.split(command) command = shlex.split(command)
pipe = subprocess.Popen(command, stdin=subprocess.PIPE, pipe = subprocess.Popen(command, stdin=subprocess.PIPE,
@@ -48,14 +53,62 @@ def sign_data(data, certificate, password_fd):
return signed_ascii return signed_ascii
def verify_data(data, signature, key_file): def get_public_key(cert_file):
""" """
Verifies signature of data signed with given key file. Extracts public key from certificate.
Arguments:
cert_file: Certificate
Returns:
Public key
"""
# Use OpenSSL to extract public key
command = "openssl x509 -inform pem -in %s -pubkey -noout"
command = command % cert_file
command = shlex.split(command)
pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
key_ascii = pipe.stdout.read()
return key_ascii
def verify_certificate(cert_file):
"""
Verifies a certificate.
Arguments:
cert_file: Certificate
Returns:
VALID, SELF_SIGNED or INVALID
"""
# Use OpenSSL to verify certificate
command = '/usr/bin/openssl verify %s'
command = command % cert_file
command = shlex.split(command)
pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
lines = pipe.stdout.read().split('\n')
if len(lines) < 2:
return INVALID
elif lines[1].startswith("error"):
code = lines[1].split()[1]
if code == '18':
return SELF_SIGNED
else:
return INVALID
else:
return VALID
def verify_data(data, signature, cert_file):
"""
Verifies signature of data signed with given certificate.
Arguments: Arguments:
data: Original data data: Original data
signature_file: Signed data signature_file: Signed data
key_file: Public keyfile cert_file: Certificate
Returns: Returns:
True if valid, False if invalid True if valid, False if invalid
""" """
@@ -69,9 +122,14 @@ def verify_data(data, signature, key_file):
data_file.write(data) data_file.write(data)
data_file.flush() data_file.flush()
# Keep public key in a temporary file
pub_file = tempfile.NamedTemporaryFile()
pub_file.write(get_public_key(cert_file))
pub_file.flush()
# Use OpenSSL to verify signature # Use OpenSSL to verify signature
command = '/usr/bin/openssl dgst -sha1 -verify %s -signature %s %s' command = '/usr/bin/openssl dgst -sha1 -verify %s -signature %s %s'
command = command % (key_file, signature_file.name, data_file.name) command = command % (pub_file.name, signature_file.name, data_file.name)
command = shlex.split(command) command = shlex.split(command)
pipe = subprocess.Popen(command, stdout=subprocess.PIPE, pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
@@ -81,6 +139,7 @@ def verify_data(data, signature, key_file):
# Destroy temporary files # Destroy temporary files
signature_file.close() signature_file.close()
data_file.close() data_file.close()
pub_file.close()
return result == 0 return result == 0
@@ -107,13 +166,13 @@ def get_zip_hashes(zip_obj):
return "\n".join(hashes) return "\n".join(hashes)
def verify_zipfile(filename, key_file): def verify_zipfile(filename, cert_file):
""" """
Verifies integrity of a ZIP file. Verifies integrity of a ZIP file.
Arguments: Arguments:
filename: ZIP filename filename: ZIP filename
key_file: Public keyfile cert_file: Certificate
Returns: Returns:
True if valid, False if invalid True if valid, False if invalid
""" """
@@ -133,7 +192,7 @@ def verify_zipfile(filename, key_file):
zip_obj.close() zip_obj.close()
# Verify signed data # Verify signed data
return verify_data(hashes, signature, key_file) return verify_data(hashes, signature, cert_file)
def sign_zipfile(filename, certificate, password_fd): def sign_zipfile(filename, certificate, password_fd):
""" """
@@ -164,7 +223,7 @@ def print_usage():
print "Usage:" print "Usage:"
print " %s sign <path/to/private_key> <file.zip ...>" % sys.argv[0] print " %s sign <path/to/private_key> <file.zip ...>" % sys.argv[0]
print " %s verify <path/to/public_key> <file.zip ...>" % sys.argv[0] print " %s verify <path/to/certificate> <file.zip ...>" % sys.argv[0]
sys.exit(1) sys.exit(1)
def main(): def main():
@@ -201,13 +260,20 @@ def main():
elif operation == 'verify': elif operation == 'verify':
try: try:
key_file = sys.argv[2] cert_file = sys.argv[2]
except IndexError: except IndexError:
print_usage() print_usage()
cert_validity = verify_certificate(cert_file)
if cert_validity == SELF_SIGNED:
print "WARNING: Certificate is self-signed."
elif cert_validity == INVALID:
print "ERROR: Certificate is invalid"
sys.exit(1)
if len(sys.argv[3:]): if len(sys.argv[3:]):
for filename in sys.argv[3:]: for filename in sys.argv[3:]:
if verify_zipfile(filename, key_file): if verify_zipfile(filename, cert_file):
print "%s is valid." % filename print "%s is valid." % filename
else: else:
print "%s is corrupted." % filename print "%s is corrupted." % filename