blob: 480a4ef401628d143fb582215021a130b4c3ee26 [file] [log] [blame]
/*
* Copyright (c) 2021 Apple 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
*
* https://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.
*
* This file contains function declarations for tls-keychain.c, which deals
* with TLS certificate fetching and evaluation.
*/
#ifndef __TLS_KEYCHAIN_H__
#define __TLS_KEYCHAIN_H__
#if __APPLE__
#include <Security/Security.h>
#endif
//======================================================================================================================
// MARK: - Macros
#define SRP_APPLICATION_IDENTIFIER "com.apple.srp-mdns-proxy" // Application identifier for srp-mdns-proxy
#define DNSSD_PROXY_APPLICATION_IDENTIFIER "com.apple.dnssd-proxy" // Application identifier for dnssd-proxy
#define KEYCHAIN_ACCESS_GROUP SRP_APPLICATION_IDENTIFIER // Keychain access group of dnssd-proxy and mDNSResponder
#define DNSSD_PROXY_IDENTITY_NAME SRP_APPLICATION_IDENTIFIER " identity" // The identity name used by dnssd-proxy
#define KEY_ATTRIBUTE_LABEL_PREFIX "Key " // User-visible string put into the attribute label of the private key
#define CERTIFICATE_ATTRIBUTE_LABEL_PREFIX "Certificate " // User-visible string put into the attribute label of the certificate
// The TLS certificate in the keychain will be updated every two weeks(1209600s).
#define TLS_CERTIFICATE_VALID_PERIOD_SECS 1209600
// The TLS certificate that has been created for more than four weeks(2419200s) will be deleted from iCloud keychain no
// matter who creates it.
#define TLS_CERTIFICATE_EXISTENCE_PERIOD_SECS (TLS_CERTIFICATE_VALID_PERIOD_SECS * 2)
//======================================================================================================================
// MARK: - Structures
// Context set in sec_protocol_options_set_verify_block() when trying to setup TLS connection with the server.
typedef struct tls_keychain_context_t tls_keychain_context_t;
struct tls_keychain_context_t {
#if __APPLE__
sec_protocol_metadata_t _Nonnull metadata;
sec_trust_t _Nonnull trust_ref;
#else // __APPLE__
uint8_t not_a_real_member;
#endif // __APPLE__
};
//======================================================================================================================
// MARK: - Functions
/*!
* @brief
* Get the TLS certificate from the iCloud keychain.
*
* @result
* True if the operation succeeds, otherwise, false.
*/
bool
tls_cert_init(void);
/*!
* @brief
* Given the context, verify if the current TLS certificate should be trusted or not.
*
* @param context
* Variables that are required to finish the TLS certificate evaluation.
*
* @result
* True if it is trusted, false if not.
*/
bool
tls_cert_evaluate(const tls_keychain_context_t * _Nonnull context);
/*!
* @brief
* Release the TLS certificate get from iCloud keychain.
*
* @discussion
* If the certificate has been fetched from iCloud keychain, it will be released. If not, nothing will happen.
*/
void
tls_cert_dispose(void);
#ifdef __APPLE__
/*!
* @brief
* Add the identity into keychain.
*
* @param identity
* A SecIdentityRef that contains a pair of SecKeyRef private key and SecCertificateRef certificate.
*
* @param uuid
* An UUID that will be used to set three properties of the SecIdentityRef containing a pair of SecKeyRef and SecCertificateRef:
* 1. UUID is used to set SecKeyRef's attribute label: "Key <UUID>".
* 2. UUID is used to set SecCertificate's attribute label: "Certificate <UUID>".
* 3. UUID is used to set the common name property in the subjects of SecCertificateRef: "<App Identifier> <UUID>".
* All the properties set above are used to match the specific SecItem when manipulating them.
*
* @result
* errSecSuccess if the identity is added into keychain successfully, otherwise, an error code to indicate the error.
*
* @discussion
* When an identity is added into keychain, the private key part of the identity will remain locally, and it will not be synced to iCloud keychain.
* The certificate part of the identity will be synced to iCloud keychain.
*/
OSStatus
keychain_identity_add(const SecIdentityRef _Nonnull identity, const CFStringRef _Nonnull uuid);
/*!
* @brief
* Retrieve the identity added by <code>keychain_identity_add()</code> on the same device.
*
* @param out_identity
* A pointer to a SecIdentityRef variable that can be used to return the retrieved identity.
*
* @param out_identity_creation_time
* A pointer to a CFAbsoluteTime variable that can be used to return the creation time of the identity.
*
* @result
* errSecSuccess if the identity is found, errSecItemNotFound if the identity is not found, otherwise, an error code to indicate the error.
*
* @discussion
* Note that the identity being returned here is the one that gets added by <code>keychain_identity_add()</code> on the same device.
* Which means the identity can only be returned to its creator by this function.
*/
OSStatus
keychain_identity_copy(CF_RETURNS_RETAINED SecIdentityRef * _Nonnull out_identity,
CFAbsoluteTime * _Nonnull out_identity_creation_time);
/*!
* @brief
* Remove the identity added by <code>keychain_identity_add()</code> on the same device.
*
* @result
* errSecSuccess if the identity is removed from keychain, errSecItemNotFound if the identity is not found. Otherwise, an error code to indicate the error.
*
* @discussion
* Here the identity is said to be removed from keychain if:
* 1. The private key of the identity is removed from the local keychain.
* 2. The certificate of the identity is removed from the iCloud keychain.
*/
OSStatus
keychain_identity_remove(void);
/*!
* @brief
* Retrieve all the certificates from iCloud keychain that are added by <code>keychain_identity_add()</code>.
*
* @param out_certificates
* A pointer to a CFArrayRef variable that can be used to return the retrieved SecCertificateRef array.
*
* @param return_attributes
* A boolean value that determines whether it should return the attributes dictionary for the certificates or not.
*
* @result
* errSecSuccess if the certificates on the iCloud keychain are found, errSecItemNotFound if the certificates are not found, otherwise an error code to indicate
* the error.
*/
OSStatus
keychain_certificates_copy(CF_RETURNS_RETAINED CFArrayRef * const _Nonnull out_certificates,
bool return_attributes);
/*!
* @brief
* Removes all the certificates that are more than TLS_CERTIFICATE_EXISTENCE_PERIOD_SECS seconds old.
*
* @result
* errSecSuccess if there is any expired certificate that has been removed from keychain, errSecItemNotFound if the identity is not found. Otherwise, an error
* code to indicate the error.
*/
OSStatus
keychain_certificates_remove_expired(void);
#endif // __APPLE__
#endif // __TLS_KEYCHAIN_H__