-
-
Notifications
You must be signed in to change notification settings - Fork 345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve memory management of SSL fingerprint data #1618
Changes from 2 commits
a718c2b
6d992fe
9989ef9
16732c4
fd0f801
ed1ce28
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,15 +14,107 @@ enum SslFingerprintType { | |
// Only when the private key used to generate the certificate is used then that fingerprint | ||
}; | ||
|
||
typedef struct { | ||
/** @brief Contains SSL fingerprint data | ||
* @note Lifetime as follows: | ||
* - Constructed by application, using appropriate setXXX method; | ||
* - Passed into HttpRequest by application, using pinCertificate method - request is then queued; | ||
* - Passed into HttpConnection (TcpClient descendant) by HttpClient, using pinCertificate method | ||
* - When certificate validated, memory is released | ||
* | ||
*/ | ||
struct SslFingerprints { | ||
uint8_t* certSha1 = nullptr; // << certificate SHA1 fingerprint | ||
uint8_t* pkSha256 = nullptr; // << public key SHA256 fingerprint | ||
|
||
~SslFingerprints() | ||
{ | ||
free(); | ||
} | ||
|
||
void free() | ||
{ | ||
delete certSha1; | ||
delete[] certSha1; | ||
certSha1 = nullptr; | ||
delete pkSha256; | ||
delete[] pkSha256; | ||
pkSha256 = nullptr; | ||
} | ||
} SslFingerprints; | ||
|
||
bool setSha1(const uint8_t* cert, unsigned length) | ||
{ | ||
return setValue(certSha1, SHA1_SIZE, cert, length); | ||
} | ||
|
||
bool setSha256(const uint8_t* cert, unsigned length) | ||
{ | ||
return setValue(pkSha256, SHA256_SIZE, cert, length); | ||
} | ||
|
||
/** @brief Make copy of SHA1 certificate from data stored in flash | ||
* @param cert | ||
*/ | ||
bool setSha1_P(const uint8_t* cert, unsigned length) | ||
{ | ||
// Word-aligned and sized buffers don't need special handling | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the word-aligning planned to be added here? If not then this method is identical to the non _P versions and my question is why is that needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a matter of semantics; it also means we could add an optimisation internally which avoids copying the fingerprint data but instead takes a reference to it. I can do that if you want to stick with this model, but I'd also change to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Let's leave this change for now and schedule it for the next version. |
||
return setSha1(cert, length); | ||
} | ||
|
||
/** @brief Make copy of SHA256 certificate from data stored in flash | ||
* @param cert | ||
*/ | ||
bool setSha256_P(const uint8_t* cert, unsigned length) | ||
{ | ||
// Word-aligned and sized buffers don't need special handling | ||
return setSha256(cert, length); | ||
} | ||
|
||
/** @brief Moves values out of source */ | ||
SslFingerprints& operator=(SslFingerprints& source) | ||
{ | ||
delete[] certSha1; | ||
mikee47 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
certSha1 = source.certSha1; | ||
source.certSha1 = nullptr; | ||
|
||
delete[] pkSha256; | ||
pkSha256 = source.pkSha256; | ||
source.pkSha256 = nullptr; | ||
|
||
return *this; | ||
} | ||
|
||
/** @brief Make copy of values from source */ | ||
SslFingerprints& operator=(const SslFingerprints& source) | ||
{ | ||
setSha1(source.certSha1, SHA1_SIZE); | ||
mikee47 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
setSha256(source.pkSha256, SHA256_SIZE); | ||
|
||
return *this; | ||
} | ||
|
||
private: | ||
/** @brief Internal method to set a fingerprint | ||
* @param value Reference to fingerprint value in this structure | ||
* @param length Required length for value | ||
* @param newValue | ||
* @param newLength | ||
* @retval bool true on success, false on invalid length or memory allocation failure | ||
*/ | ||
bool setValue(uint8_t*& value, unsigned length, const uint8_t* newValue, unsigned newLength) | ||
mikee47 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if(newValue == nullptr || newLength == 0) { | ||
delete[] value; | ||
value = nullptr; | ||
return true; | ||
} else if(newLength != length) { | ||
return false; | ||
} else { | ||
if(value == nullptr) { | ||
value = new uint8_t[length]; | ||
if(value == nullptr) { | ||
return false; | ||
} | ||
} | ||
memcpy(value, newValue, length); | ||
return true; | ||
} | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... Do we need those specific types or more general ones would be better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do wonder if we need
StreamType
at all? In the framework it's barely used:IDataSourceStream::isValid()
Inherited classes can just override this method directly, rather than returning
eSST_Invalid
fromgetStreamType()
HttpRequest::getBody()
andHttpResponse::getBody()
Both of these fail if the stream type isn't
eSST_Memory
, but I'm not sure that check is even necessary.So we could fix these points and deprecate the
getStreamType()
method completely. We changeIDataSourceStream::getStreamType()
to returneSST_Unknown
and remove it fromHardwareSerial
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good to me. Just make sure that it is in a separate PR.