Home | History | Annotate | Line # | Download | only in mDNSShared
      1 /*
      2  * Copyright (c) 2021-2024 Apple Inc. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     https://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  *
     16  * This file contains function declarations for tls-keychain.c, which deals
     17  * with TLS certificate fetching and evaluation.
     18  */
     19 
     20 #ifndef __TLS_KEYCHAIN_H__
     21 #define __TLS_KEYCHAIN_H__
     22 
     23 #if __APPLE__
     24 #include <Security/Security.h>
     25 #endif
     26 
     27 //======================================================================================================================
     28 // MARK: - Macros
     29 
     30 #define SRP_APPLICATION_IDENTIFIER "com.apple.srp-mdns-proxy" // Application identifier for srp-mdns-proxy
     31 #define DNSSD_PROXY_APPLICATION_IDENTIFIER "com.apple.dnssd-proxy" // Application identifier for dnssd-proxy
     32 #define KEYCHAIN_ACCESS_GROUP SRP_APPLICATION_IDENTIFIER // Keychain access group of dnssd-proxy and mDNSResponder
     33 #define DNSSD_PROXY_IDENTITY_NAME SRP_APPLICATION_IDENTIFIER " identity" // The identity name used by dnssd-proxy
     34 #define KEY_ATTRIBUTE_LABEL_PREFIX "Key " // User-visible string put into the attribute label of the private key
     35 #define CERTIFICATE_ATTRIBUTE_LABEL_PREFIX "Certificate " // User-visible string put into the attribute label of the certificate
     36 
     37 // The TLS certificate in the keychain will be updated every two weeks(1209600s).
     38 #define TLS_CERTIFICATE_VALID_PERIOD_SECS 1209600
     39 // The TLS certificate that has been created for more than four weeks(2419200s) will be deleted from iCloud keychain no
     40 // matter who creates it.
     41 #define TLS_CERTIFICATE_EXISTENCE_PERIOD_SECS (TLS_CERTIFICATE_VALID_PERIOD_SECS * 2)
     42 
     43 //======================================================================================================================
     44 // MARK: - Structures
     45 
     46 // Context set in sec_protocol_options_set_verify_block() when trying to setup TLS connection with the server.
     47 typedef struct tls_keychain_context_t tls_keychain_context_t;
     48 struct tls_keychain_context_t {
     49 #if __APPLE__
     50 	sec_protocol_metadata_t _Nonnull metadata;
     51 	sec_trust_t _Nonnull trust_ref;
     52 	bool trusts_alternative_server_certificates;
     53 #else // __APPLE__
     54 	uint8_t not_a_real_member;
     55 #endif // __APPLE__
     56 };
     57 
     58 //======================================================================================================================
     59 // MARK: - Functions
     60 
     61 /*!
     62  *	@brief
     63  *		Get the TLS certificate from the iCloud keychain.
     64  *
     65  *	@result
     66  *		True if the operation succeeds, otherwise, false.
     67  */
     68 bool
     69 tls_cert_init(void);
     70 
     71 /*!
     72  *	@brief
     73  *		Specify alternative trusted TLS certificates that can be used to perform trust evaluation.
     74  *
     75  *	@param certs
     76  *		An array of TLS certificates as CFDataRef objects.
     77  *
     78  *	@result
     79  *		kNoErr if the trusted server certificates were successfully updated. Otherwise, a non-zero error code to indicate why
     80  *		the operation failed.
     81  *
     82  *	@discussion
     83  *		Calling this function for the second time after the first call overrides the previously configured certificates.
     84  *		Calling this function with NULL clears any alternative certificate that we have trusted before.
     85  */
     86 OSStatus
     87 tls_cert_set_alternative_trusted_certificates(CFArrayRef _Nullable certs);
     88 
     89 /*!
     90  *	@brief
     91  *		Given the context, verify if the current TLS certificate should be trusted or not.
     92  *
     93  *	@param context
     94  *		Variables that are required to finish the TLS certificate evaluation.
     95  *
     96  *	@result
     97  *		True if it is trusted, false if not.
     98  */
     99 bool
    100 tls_cert_evaluate(const tls_keychain_context_t * _Nonnull context);
    101 
    102 /*!
    103  *	@brief
    104  *		Release the TLS certificate get from iCloud keychain.
    105  *
    106  *	@discussion
    107  *		If the certificate has been fetched from iCloud keychain, it will be released. If not, nothing will happen.
    108  */
    109 void
    110 tls_cert_dispose(void);
    111 
    112 #ifdef __APPLE__
    113 
    114 /*!
    115  *	@brief
    116  *		Add the identity into keychain.
    117  *
    118  *	@param identity
    119  *		A SecIdentityRef that contains a pair of SecKeyRef private key and SecCertificateRef certificate.
    120  *
    121  *	@param uuid
    122  *		An UUID that will be used to set three properties of the SecIdentityRef containing a pair of SecKeyRef and SecCertificateRef:
    123  *		1. UUID is used to set SecKeyRef's attribute label: "Key <UUID>".
    124  *		2. UUID is used to set SecCertificate's attribute label: "Certificate <UUID>".
    125  *		3. UUID is used to set the common name property in the subjects of SecCertificateRef: "<App Identifier> <UUID>".
    126  *		All the properties set above are used to match the specific SecItem when manipulating them.
    127  *
    128  *	@result
    129  *		errSecSuccess if the identity is added into keychain successfully, otherwise, an error code to indicate the error.
    130  *
    131  *	@discussion
    132  *		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.
    133  *		The certificate part of the identity will be synced to iCloud keychain.
    134  */
    135 OSStatus
    136 keychain_identity_add(const SecIdentityRef _Nonnull identity, const CFStringRef _Nonnull uuid);
    137 
    138 /*!
    139  *	@brief
    140  *		Retrieve the identity added by <code>keychain_identity_add()</code> on the same device.
    141  *
    142  *	@param out_identity
    143  * 		A pointer to a SecIdentityRef variable that can be used to return the retrieved identity.
    144  *
    145  *	@param out_identity_creation_time
    146  * 		A pointer to a CFAbsoluteTime variable that can be used to return the creation time of the identity.
    147  *
    148  *	@result
    149  * 		errSecSuccess if the identity is found, errSecItemNotFound if the identity is not found, otherwise, an error code to indicate the error.
    150  *
    151  *	@discussion
    152  * 		Note that the identity being returned here is the one that gets added by <code>keychain_identity_add()</code> on the same device.
    153  * 		Which means the identity can only be returned to its creator by this function.
    154  */
    155 OSStatus
    156 keychain_identity_copy(CF_RETURNS_RETAINED SecIdentityRef * _Nonnull out_identity,
    157 					   CFAbsoluteTime * _Nonnull out_identity_creation_time);
    158 
    159 /*!
    160  *	@brief
    161  *		Remove the identity added by <code>keychain_identity_add()</code> on the same device.
    162  *
    163  *	@result
    164  *		errSecSuccess if the identity is removed from keychain, errSecItemNotFound if the identity is not found. Otherwise, an error code to indicate the error.
    165  *
    166  *	@discussion
    167  *		Here the identity is said to be removed from keychain if:
    168  *		1. The private key of the identity is removed from the local keychain.
    169  *		2. The certificate of the identity is removed from the iCloud keychain.
    170  */
    171 OSStatus
    172 keychain_identity_remove(void);
    173 
    174 /*!
    175  *	@brief
    176  *		Retrieve all the certificates from iCloud keychain that are added by <code>keychain_identity_add()</code>.
    177  *
    178  *	@param out_certificates
    179  *		A pointer to a CFArrayRef variable that can be used to return the retrieved SecCertificateRef array.
    180  *
    181  *	@result
    182  *		errSecSuccess if the certificates on the iCloud keychain are found, errSecItemNotFound if the certificates are not found, otherwise an error code to indicate
    183  *		the error.
    184  */
    185 OSStatus
    186 keychain_certificates_copy(CF_RETURNS_RETAINED CFArrayRef * const _Nonnull out_certificates);
    187 
    188 /*!
    189  *	@brief
    190  *		Removes all the certificates that are more than TLS_CERTIFICATE_EXISTENCE_PERIOD_SECS seconds old.
    191  *
    192  *	@result
    193  *		errSecSuccess if there is any expired certificate that has been removed from keychain, errSecItemNotFound if the identity is not found. Otherwise, an error
    194  *		code to indicate the error.
    195  */
    196 OSStatus
    197 keychain_certificates_remove_expired(void);
    198 
    199 #endif // __APPLE__
    200 
    201 #endif // __TLS_KEYCHAIN_H__
    202