This repository has been archived by the owner on Jul 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bug: decode and process crypto-key header correctly
The Crypto-Key header has a different format than what was first understood. A valid Crypto-Key header may look like `keyid="foo"; key1="data",key2="data"`. This patch specialized Crypto-Key parsing to a class. Closes #410
- Loading branch information
Showing
6 changed files
with
162 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
"""Crypto-Key header parser and manager""" | ||
|
||
|
||
class CryptoKeyException(Exception): | ||
"""Invalid CryptoKey""" | ||
|
||
|
||
class CryptoKey(object): | ||
"""Parse the Crypto-Key header per | ||
http://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00#section-4 | ||
""" | ||
_values_ = [] | ||
|
||
def __init__(self, header): | ||
"""Parse the Crypto-Key header | ||
:param header: Header content string. | ||
""" | ||
chunks = header.split(",") | ||
if self._values_: | ||
self._values_ = [] | ||
for chunk in chunks: | ||
bits = chunk.split(";") | ||
hash = {} | ||
for bit in bits: | ||
try: | ||
(key, value) = bit.split("=", 1) | ||
except ValueError: | ||
raise CryptoKeyException("Invalid Crypto Key value") | ||
hash[key.strip()] = value.strip(' "') | ||
self._values_.append(hash) | ||
|
||
def get_keyid(self, keyid): | ||
"""Return the Crypto-Key hash referred to by a given keyid. | ||
For example, for a CryptoKey specified as: | ||
Crypto-Key: keyid="apple";foo="fruit",keyid="gorp";bar="snake" | ||
get_keyid("apple") would return a hash of | ||
{"keyid": "apple", "foo":"fruit"} | ||
:param keyid: The keyid to reference | ||
:returns: hash of the matching key data or None | ||
""" | ||
for val in self._values_: | ||
if keyid == val.get('keyid'): | ||
return val | ||
return None | ||
|
||
def get_label(self, label): | ||
"""Return the Crypto-Key value referred to by a given label. | ||
For example, for a CryptoKey specified as: | ||
Crypto-Key: keyid="apple";foo="fruit",keyid="gorp";bar="snake" | ||
get_label("foo") | ||
would return a value of "apple" | ||
**NOTE** This presumes that "label" is unique. Otherwise it will | ||
only return the FIRST instance of "label". Use get_keyid() if | ||
you know of multiple sections containing similar labels. | ||
:param label: The label to reference. | ||
:returns: Value associated with the key data or None | ||
""" | ||
for val in self._values_: | ||
if label in val: | ||
return val.get(label) | ||
return None | ||
|
||
def to_string(self): | ||
"""Return a reformulated Crypto-Key header string""" | ||
chunks = [] | ||
for val in self._values_: | ||
bits = [] | ||
for key in val: | ||
bits.append("{}=\"{}\"".format(key, val[key])) | ||
chunks.append(';'.join(bits)) | ||
return ','.join(chunks) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import unittest | ||
|
||
from nose.tools import (eq_, ok_) | ||
|
||
from autopush.crypto_key import CryptoKey | ||
|
||
|
||
class CryptoKeyTestCase(unittest.TestCase): | ||
|
||
valid_key = ( | ||
'keyid="p256dh";dh="BDw9T0eImd4ax818VcYqDK_DOhcuDswKero' | ||
'YyNkdhYmygoLSDlSiWpuoWYUSSFxi25cyyNTR5k9Ny93DzZc0UI4",' | ||
'p256ecdsa="BF92zdI_AKcH5Q31_Rr-04bPqOHU_Qg6lAawHbvfQrY' | ||
'xV_vIsAsHSyaiuyfofvxT8ZVIXccykd4V2Z7iJVfreT8"') | ||
|
||
def test_parse(self): | ||
ckey = CryptoKey(self.valid_key) | ||
eq_(ckey.get_keyid("p256dh"), | ||
{"keyid": "p256dh", | ||
"dh": "BDw9T0eImd4ax818VcYqDK_DOhcuDswKero" | ||
"YyNkdhYmygoLSDlSiWpuoWYUSSFxi25cyyNTR5k9Ny93DzZc0UI4"}) | ||
eq_(ckey.get_label("p256ecdsa"), | ||
"BF92zdI_AKcH5Q31_Rr-04bPqOHU_Qg6lAawHbvfQrY" | ||
"xV_vIsAsHSyaiuyfofvxT8ZVIXccykd4V2Z7iJVfreT8") | ||
ok_(ckey.get_keyid("missing") is None) | ||
ok_(ckey.get_label("missing") is None) | ||
|
||
def test_parse_lenient(self): | ||
ckey = CryptoKey(self.valid_key.replace('"', '')) | ||
str = ckey.to_string() | ||
ckey2 = CryptoKey(str) | ||
ok_(ckey.get_keyid("p256dh"), ckey2.get_keyid("p256dh")) | ||
ok_(ckey.get_label("p256ecdsa") is not None) | ||
ok_(ckey.get_label("p256ecdsa"), ckey2.get_label("p256ecdsa")) | ||
|
||
def test_string(self): | ||
ckey = CryptoKey(self.valid_key) | ||
str = ckey.to_string() | ||
ckey2 = CryptoKey(str) | ||
ok_(ckey.get_keyid("p256dh"), ckey2.get_keyid("p256dh")) | ||
ok_(ckey.get_label("p256ecdsa") is not None) | ||
ok_(ckey.get_label("p256ecdsa"), ckey2.get_label("p256ecdsa")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.