Revision 68857643 lib/utils.py
b/lib/utils.py | ||
---|---|---|
47 | 47 |
import OpenSSL |
48 | 48 |
import datetime |
49 | 49 |
import calendar |
50 |
import hmac |
|
50 | 51 |
|
51 | 52 |
from cStringIO import StringIO |
52 | 53 |
|
53 | 54 |
try: |
54 | 55 |
from hashlib import sha1 |
55 | 56 |
except ImportError: |
56 |
import sha |
|
57 |
sha1 = sha.new |
|
57 |
import sha as sha1 |
|
58 | 58 |
|
59 | 59 |
from ganeti import errors |
60 | 60 |
from ganeti import constants |
... | ... | |
70 | 70 |
|
71 | 71 |
_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid" |
72 | 72 |
|
73 |
HEX_CHAR_RE = r"[a-zA-Z0-9]" |
|
74 |
VALID_X509_SIGNATURE_SALT = re.compile("^%s+$" % HEX_CHAR_RE, re.S) |
|
75 |
X509_SIGNATURE = re.compile(r"^%s:\s*(?P<salt>%s+)/(?P<sign>%s+)$" % |
|
76 |
(re.escape(constants.X509_CERT_SIGNATURE_HEADER), |
|
77 |
HEX_CHAR_RE, HEX_CHAR_RE), |
|
78 |
re.S | re.I) |
|
79 |
|
|
73 | 80 |
|
74 | 81 |
class RunResult(object): |
75 | 82 |
"""Holds the result of running external programs. |
... | ... | |
673 | 680 |
|
674 | 681 |
f = open(filename) |
675 | 682 |
|
676 |
fp = sha1() |
|
683 |
if callable(sha1): |
|
684 |
fp = sha1() |
|
685 |
else: |
|
686 |
fp = sha1.new() |
|
677 | 687 |
while True: |
678 | 688 |
data = f.read(4096) |
679 | 689 |
if not data: |
... | ... | |
2356 | 2366 |
return (not_before, not_after) |
2357 | 2367 |
|
2358 | 2368 |
|
2369 |
def SignX509Certificate(cert, key, salt): |
|
2370 |
"""Sign a X509 certificate. |
|
2371 |
|
|
2372 |
An RFC822-like signature header is added in front of the certificate. |
|
2373 |
|
|
2374 |
@type cert: OpenSSL.crypto.X509 |
|
2375 |
@param cert: X509 certificate object |
|
2376 |
@type key: string |
|
2377 |
@param key: Key for HMAC |
|
2378 |
@type salt: string |
|
2379 |
@param salt: Salt for HMAC |
|
2380 |
@rtype: string |
|
2381 |
@return: Serialized and signed certificate in PEM format |
|
2382 |
|
|
2383 |
""" |
|
2384 |
if not VALID_X509_SIGNATURE_SALT.match(salt): |
|
2385 |
raise errors.GenericError("Invalid salt: %r" % salt) |
|
2386 |
|
|
2387 |
# Dumping as PEM here ensures the certificate is in a sane format |
|
2388 |
cert_pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) |
|
2389 |
|
|
2390 |
return ("%s: %s/%s\n\n%s" % |
|
2391 |
(constants.X509_CERT_SIGNATURE_HEADER, salt, |
|
2392 |
hmac.new(key, salt + cert_pem, sha1).hexdigest(), |
|
2393 |
cert_pem)) |
|
2394 |
|
|
2395 |
|
|
2396 |
def _ExtractX509CertificateSignature(cert_pem): |
|
2397 |
"""Helper function to extract signature from X509 certificate. |
|
2398 |
|
|
2399 |
""" |
|
2400 |
# Extract signature from original PEM data |
|
2401 |
for line in cert_pem.splitlines(): |
|
2402 |
if line.startswith("---"): |
|
2403 |
break |
|
2404 |
|
|
2405 |
m = X509_SIGNATURE.match(line.strip()) |
|
2406 |
if m: |
|
2407 |
return (m.group("salt"), m.group("sign")) |
|
2408 |
|
|
2409 |
raise errors.GenericError("X509 certificate signature is missing") |
|
2410 |
|
|
2411 |
|
|
2412 |
def LoadSignedX509Certificate(cert_pem, key): |
|
2413 |
"""Verifies a signed X509 certificate. |
|
2414 |
|
|
2415 |
@type cert_pem: string |
|
2416 |
@param cert_pem: Certificate in PEM format and with signature header |
|
2417 |
@type key: string |
|
2418 |
@param key: Key for HMAC |
|
2419 |
@rtype: tuple; (OpenSSL.crypto.X509, string) |
|
2420 |
@return: X509 certificate object and salt |
|
2421 |
|
|
2422 |
""" |
|
2423 |
(salt, signature) = _ExtractX509CertificateSignature(cert_pem) |
|
2424 |
|
|
2425 |
# Load certificate |
|
2426 |
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_pem) |
|
2427 |
|
|
2428 |
# Dump again to ensure it's in a sane format |
|
2429 |
sane_pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) |
|
2430 |
|
|
2431 |
if signature != hmac.new(key, salt + sane_pem, sha1).hexdigest(): |
|
2432 |
raise errors.GenericError("X509 certificate signature is invalid") |
|
2433 |
|
|
2434 |
return (cert, salt) |
|
2435 |
|
|
2436 |
|
|
2359 | 2437 |
def SafeEncode(text): |
2360 | 2438 |
"""Return a 'safe' version of a source string. |
2361 | 2439 |
|
Also available in: Unified diff