blob: 283956977625f5e5de534f3451f79f13f953d29c [file] [log] [blame]
/*
*
* Copyright (c) 2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Utility functions for interacting with Weave Access Tokens.
*
*/
#include <Weave/Core/WeaveCore.h>
#include <Weave/Profiles/WeaveProfiles.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Support/ASN1.h>
#include <Weave/Support/crypto/HashAlgos.h>
#include <Weave/Support/crypto/EllipticCurve.h>
#include <Weave/Profiles/security/WeaveSecurity.h>
#include <Weave/Profiles/security/WeaveCert.h>
#include <Weave/Support/CodeUtils.h>
#include "WeaveAccessToken.h"
namespace nl {
namespace Weave {
namespace Profiles {
namespace Security {
using namespace nl::Weave::ASN1;
using namespace nl::Weave::TLV;
using namespace nl::Weave::Profiles;
using namespace nl::Weave::Crypto;
/**
* @brief
* Load the certificates in an access token into a Weave certificate set.
*
* @details
* This function decodes a given Weave access token and loads the access token certificates into the
* specified Weave certificate set object. If the access tokens contains one or more related certificate
* these are loaded into the certificate set as well.
*
* @param accessToken A pointer to a buffer containing an encoded Weave Access Token.
* @param accessTokenLen The length of the encoded access token.
* @param certSet The certificate set into which the access token certificates should
* be loaded.
* @param devodeFlags The certificate decode flags that should be used when loading
* the certificates.
* @param accessTokenCert A reference to a pointer that will be set to the Weave certificate
* data structure for the access token certificate. NOTE: This
* pointer will only be set if the function returns successfully.
*
* @retval #WEAVE_NO_ERROR If the access token certificates were successfully loaded.
* @retval tlv-errors Weave errors related to reading TLV.
* @retval cert-errors Weave errors related to decoding Weave certificates.
* @retval platform-errors Other platform-specific errors.
*/
WEAVE_ERROR LoadAccessTokenCerts(const uint8_t *accessToken, uint32_t accessTokenLen, WeaveCertificateSet& certSet, uint16_t decodeFlags, WeaveCertificateData *& accessTokenCert)
{
TLVReader reader;
reader.Init(accessToken, accessTokenLen);
return LoadAccessTokenCerts(reader, certSet, decodeFlags, accessTokenCert);
}
/**
* @brief
* Load the certificates in an access token into a Weave certificate set.
*
* @details
* This function reads a Weave access token from a given TLVReader and loads the access token certificates
* into the specified Weave certificate set object. If the access tokens contains one or more related
* certificate these are loaded into the certificate set as well.
*
* @param reader A TLVReader object that is position immediately before a Weave
* Access Token.
* @param certSet The certificate set into which the access token certificates should
* be loaded.
* @param devodeFlags The certificate decode flags that should be used when loading
* the certificates.
* @param accessTokenCert A reference to a pointer that will be set to the Weave certificate
* data structure for the access token certificate. NOTE: This value
* is only set when the function returns successfully.
*
* @retval #WEAVE_NO_ERROR If the access token certificates were successfully loaded.
* @retval tlv-errors Weave errors related to reading TLV.
* @retval cert-errors Weave errors related to decoding Weave certificates.
* @retval platform-errors Other platform-specific errors.
*/
WEAVE_ERROR LoadAccessTokenCerts(TLVReader& reader, WeaveCertificateSet& certSet, uint16_t decodeFlags, WeaveCertificateData *& accessTokenCert)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVType tokenContainer;
reader.ImplicitProfileId = kWeaveProfile_Security;
// Advance the reader to the start of the access token structure.
err = reader.Next(kTLVType_Structure, ProfileTag(kWeaveProfile_Security, kTag_WeaveAccessToken));
SuccessOrExit(err);
// Enter the structure.
err = reader.EnterContainer(tokenContainer);
SuccessOrExit(err);
// Advance to the first element, which should be the access token certificate.
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_Certificate));
SuccessOrExit(err);
// Load the access token certificate into the certificate set. Return a pointer to the
// cert data structure to the caller.
err = certSet.LoadCert(reader, decodeFlags, accessTokenCert);
SuccessOrExit(err);
// Advance to the private key field. (We will be ignoring this).
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_PrivateKey));
SuccessOrExit(err);
// Advance to the related certificates field. If the field is present...
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_RelatedCertificates));
if (err == WEAVE_NO_ERROR) {
// Load the related certificates into the certificate set.
err = certSet.LoadCerts(reader, decodeFlags);
SuccessOrExit(err);
}
else {
if (err == WEAVE_END_OF_TLV)
err = WEAVE_NO_ERROR;
SuccessOrExit(err);
}
// Verify there are no further fields in the access token.
err = reader.VerifyEndOfContainer();
SuccessOrExit(err);
// Exit the access token container.
err = reader.ExitContainer(tokenContainer);
SuccessOrExit(err);
exit:
return err;
}
/**
* @brief
* Reads a Weave Access Token and constructs a CASE Certificate Info TLV structure containing the
* certificates from the access token.
*
* @details
* This function decodes a given Weave Access Token and encodes the TLV for a Weave CASE Certificate
* Info structure. The EntityCertificate field within the CertificateInfo structure is set to the
* access token certificate, and the RelatedCertificates field (if present) is set to the corresponding
* field within the access token.
*
* @param accessToken A pointer to a buffer containing an encoded Weave Access Token.
* @param accessTokenLen The length of the encoded access token.
* @param certInfoBuf A pointer to a buffer into which the CASE certificate info
* structure should be encoded.
* @param certInfoBufSize The size of the buffer pointed to by certInfoBuf.
* @param certInfoLen A reference to an integer will be set to the length of the
* encoded certificate info structure. NOTE: This value is only
* set when the function returns successfully.
*
* @retval #WEAVE_NO_ERROR If the access CASE certificate info structure was successfully
* encoded.
* @retval tlv-errors Weave errors related to reading or writing TLV.
* @retval cert-errors Weave errors related to decoding Weave certificates.
* @retval platform-errors Other platform-specific errors.
*/
WEAVE_ERROR CASECertInfoFromAccessToken(const uint8_t *accessToken, uint32_t accessTokenLen, uint8_t *certInfoBuf, uint16_t certInfoBufSize, uint16_t& certInfoLen)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVReader reader;
TLVWriter writer;
reader.Init(accessToken, accessTokenLen);
writer.Init(certInfoBuf, certInfoBufSize);
writer.ImplicitProfileId = kWeaveProfile_Security;
err = CASECertInfoFromAccessToken(reader, writer);
SuccessOrExit(err);
err = writer.Finalize();
SuccessOrExit(err);
certInfoLen = writer.GetLengthWritten();
exit:
return err;
}
/**
* @brief
* Reads a Weave Access Token and writes a CASE Certificate Info TLV structure containing the
* certificates from the access token.
*
* @details
* This function reads a Weave Access Token from a given TLVReader and writes the TLV for a Weave CASE Certificate
* Info structure to a TLVWriter. The EntityCertificate field within the CertificateInfo structure is set to the
* access token certificate, and the RelatedCertificates field (if present) is set to the corresponding
* field within the access token.
*
* @param accessToken A pointer to a buffer containing an encoded Weave Access Token.
* @param accessTokenLen The length of the encoded access token.
* @param certInfoBuf A pointer to a buffer into which the CASE certificate info
* structure should be encoded.
* @param certInfoBufSize The size of the buffer pointed to by certInfoBuf.
* @param certInfoLen A reference to an integer will be set to the length of the
* encoded certificate info structure. NOTE: This value is only
* set when the function returns successfully.
*
* @retval #WEAVE_NO_ERROR If the access CASE certificate info structure was successfully
* encoded.
* @retval tlv-errors Weave errors related to reading or writing TLV.
* @retval cert-errors Weave errors related to decoding Weave certificates.
* @retval platform-errors Other platform-specific errors.
*/
WEAVE_ERROR CASECertInfoFromAccessToken(TLVReader& reader, TLVWriter& writer)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVType tokenContainer;
TLVType certInfoContainer;
reader.ImplicitProfileId = kWeaveProfile_Security;
// Advance the reader to the start of the access token structure.
err = reader.Next(kTLVType_Structure, ProfileTag(kWeaveProfile_Security, kTag_WeaveAccessToken));
SuccessOrExit(err);
// Enter the structure.
err = reader.EnterContainer(tokenContainer);
SuccessOrExit(err);
// Advance the reader to the first element, which should be the access token certificate.
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_Certificate));
SuccessOrExit(err);
// Write the start of the CASE cert info structure to the writer
err = writer.StartContainer(ProfileTag(kWeaveProfile_Security, kTag_WeaveCASECertificateInformation), kTLVType_Structure, certInfoContainer);
SuccessOrExit(err);
// Copy the access token certificate into the cert info structure, using the EntityCertificate tag.
err = writer.CopyContainer(ContextTag(kTag_CASECertificateInfo_EntityCertificate), reader);
SuccessOrExit(err);
// Advance the reader to the private key field. (We will be ignoring this).
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_PrivateKey));
SuccessOrExit(err);
// Advance the reader to the related certificates field. If the field is present...
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_RelatedCertificates));
if (err == WEAVE_NO_ERROR) {
// Copy the related certificates collection into the cert info structure, using the EntityCertificate tag.
err = writer.CopyContainer(ContextTag(kTag_CASECertificateInfo_RelatedCertificates), reader);
SuccessOrExit(err);
}
else {
if (err == WEAVE_END_OF_TLV)
err = WEAVE_NO_ERROR;
SuccessOrExit(err);
}
// Verify there are no further fields in the access token.
err = reader.VerifyEndOfContainer();
SuccessOrExit(err);
// Exit the access token container.
err = reader.ExitContainer(tokenContainer);
SuccessOrExit(err);
// Finish writing the cert info container.
err = writer.EndContainer(certInfoContainer);
SuccessOrExit(err);
exit:
return err;
}
WEAVE_ERROR ExtractPrivateKeyFromAccessToken(const uint8_t *accessToken, uint32_t accessTokenLen, uint8_t *privKeyBuf, uint16_t privKeyBufSize, uint16_t& privKeyLen)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVReader reader;
TLVWriter writer;
reader.Init(accessToken, accessTokenLen);
writer.Init(privKeyBuf, privKeyBufSize);
err = ExtractPrivateKeyFromAccessToken(reader, writer);
SuccessOrExit(err);
err = writer.Finalize();
SuccessOrExit(err);
privKeyLen = writer.GetLengthWritten();
exit:
return err;
}
WEAVE_ERROR ExtractPrivateKeyFromAccessToken(TLVReader& reader, TLVWriter& writer)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVType tokenContainer;
reader.ImplicitProfileId = kWeaveProfile_Security;
// Advance the reader to the start of the access token structure.
err = reader.Next(kTLVType_Structure, ProfileTag(kWeaveProfile_Security, kTag_WeaveAccessToken));
SuccessOrExit(err);
// Enter the structure.
err = reader.EnterContainer(tokenContainer);
SuccessOrExit(err);
// Advance the reader to the first element, which should be the access token certificate.
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_Certificate));
SuccessOrExit(err);
// Advance the reader to the next element, which should be the private key field.
err = reader.Next(kTLVType_Structure, ContextTag(kTag_AccessToken_PrivateKey));
SuccessOrExit(err);
// Copy the private key to the writer, changing the tag to EllipticCurvePrivateKey.
err = writer.CopyContainer(ProfileTag(kWeaveProfile_Security, kTag_EllipticCurvePrivateKey), reader);
SuccessOrExit(err);
// Exit the access token container.
err = reader.ExitContainer(tokenContainer);
SuccessOrExit(err);
exit:
return err;
}
} // namespace Security
} // namespace Profiles
} // namespace Weave
} // namespace nl