Support the TLS Feature (aka Must Staple) X.509v3 extension (RFC7633).
authorRob Stradling <rob@comodo.com>
Fri, 4 Dec 2015 14:35:43 +0000 (14:35 +0000)
committerKurt Roeckx <kurt@roeckx.be>
Thu, 10 Dec 2015 18:27:40 +0000 (19:27 +0100)
Signed-off-by: Kurt Roeckx <kurt@roeckx.be>
Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Dr. Stephen Henson <steve@openssl.org>
GH: #495, MR: #1435

13 files changed:
crypto/objects/obj_dat.h
crypto/objects/obj_mac.num
crypto/objects/objects.txt
crypto/x509v3/Makefile
crypto/x509v3/ext_dat.h
crypto/x509v3/v3_lib.c
crypto/x509v3/v3_tlsf.c [new file with mode: 0644]
crypto/x509v3/v3err.c
doc/apps/x509v3_config.pod
doc/crypto/X509V3_get_d2i.pod
include/openssl/obj_mac.h
include/openssl/x509v3.h
util/libeay.num

index d1382a2665c74529c33ae047a2c4304c7c0d4548..debf8cccf67511c697b9e436e917459b6a06d693 100644 (file)
  * [including the GNU Public Licence.]
  */
 
-#define NUM_NID 1020
-#define NUM_SN 1013
-#define NUM_LN 1013
-#define NUM_OBJ 936
+#define NUM_NID 1021
+#define NUM_SN 1014
+#define NUM_LN 1014
+#define NUM_OBJ 937
 
-static const unsigned char lvalues[6604]={
+static const unsigned char lvalues[6612]={
 0x2A,0x86,0x48,0x86,0xF7,0x0D,               /* [  0] OBJ_rsadsi */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,          /* [  6] OBJ_pkcs */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02,     /* [ 13] OBJ_md2 */
@@ -998,6 +998,7 @@ static const unsigned char lvalues[6604]={
 0x2A,0x85,0x03,0x64,0x03,                    /* [6588] OBJ_SNILS */
 0x2A,0x85,0x03,0x64,0x6F,                    /* [6593] OBJ_subjectSignTool */
 0x2A,0x85,0x03,0x64,0x70,                    /* [6598] OBJ_issuerSignTool */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x18,     /* [6603] OBJ_tlsfeature */
 };
 
 static const ASN1_OBJECT nid_objs[NUM_NID]={
@@ -2669,6 +2670,7 @@ static const ASN1_OBJECT nid_objs[NUM_NID]={
 {"grasshopper-mac","grasshopper-mac",NID_grasshopper_mac,0,NULL,0},
 {"ChaCha20-Poly1305","chacha20-poly1305",NID_chacha20_poly1305,0,NULL,0},
 {"ChaCha20","chacha20",NID_chacha20,0,NULL,0},
+{"tlsfeature","TLS Feature",NID_tlsfeature,8,&(lvalues[6603]),0},
 };
 
 static const unsigned int sn_objs[NUM_SN]={
@@ -3656,6 +3658,7 @@ static const unsigned int sn_objs[NUM_SN]={
 293,   /* "textNotice" */
 133,   /* "timeStamping" */
 106,   /* "title" */
+1020,  /* "tlsfeature" */
 682,   /* "tpBasis" */
 375,   /* "trustRoot" */
 436,   /* "ucl" */
@@ -3813,6 +3816,7 @@ static const unsigned int ln_objs[NUM_LN]={
 1007,  /* "Signing Tool of Subject" */
 143,   /* "Strong Extranet ID" */
 398,   /* "Subject Information Access" */
+1020,  /* "TLS Feature" */
 130,   /* "TLS Web Client Authentication" */
 129,   /* "TLS Web Server Authentication" */
 133,   /* "Time Stamping" */
@@ -5244,6 +5248,7 @@ static const unsigned int obj_objs[NUM_OBJ]={
 397,   /* OBJ_ac_proxying                  1 3 6 1 5 5 7 1 10 */
 398,   /* OBJ_sinfo_access                 1 3 6 1 5 5 7 1 11 */
 663,   /* OBJ_proxyCertInfo                1 3 6 1 5 5 7 1 14 */
+1020,  /* OBJ_tlsfeature                   1 3 6 1 5 5 7 1 24 */
 164,   /* OBJ_id_qt_cps                    1 3 6 1 5 5 7 2 1 */
 165,   /* OBJ_id_qt_unotice                1 3 6 1 5 5 7 2 2 */
 293,   /* OBJ_textNotice                   1 3 6 1 5 5 7 2 3 */
index 2993f5647e14c878201efb37b20dc6c20bec3fd6..5c6ffd41afd816a8161d4ee57f636cac1c9b8dba 100644 (file)
@@ -1017,3 +1017,4 @@ grasshopper_cfb           1016
 grasshopper_mac                1017
 chacha20_poly1305              1018
 chacha20               1019
+tlsfeature             1020
index 29517e3d7a486239f496793b80e70bc54f2284aa..f34609dd260d8a3fc45f7cbfc32475cce9fe2d99 100644 (file)
@@ -472,6 +472,7 @@ id-pe 10            : ac-proxying
 !Cname sinfo-access
 id-pe 11               : subjectInfoAccess     : Subject Information Access
 id-pe 14               : proxyCertInfo         : Proxy Certificate Information
+id-pe 24               : tlsfeature            : TLS Feature
 
 # PKIX policyQualifiers for Internet policy qualifiers
 id-qt 1                        : id-qt-cps             : Policy Qualifier CPS
index cd490ed914855cab275c3a603f0d6e43250ad783..775f88b5242d2ff5f83e94df60aa97a7c3ddd82e 100644 (file)
@@ -20,13 +20,13 @@ v3_prn.c v3_utl.c v3err.c v3_genn.c v3_alt.c v3_skey.c v3_akey.c v3_pku.c \
 v3_int.c v3_enum.c v3_sxnet.c v3_cpols.c v3_crld.c v3_purp.c v3_info.c \
 v3_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c v3_pcia.c v3_pci.c \
 pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \
-v3_asid.c v3_addr.c v3_scts.c
+v3_asid.c v3_addr.c v3_scts.c v3_tlsf.c
 LIBOBJ= v3_bcons.o v3_bitst.o v3_conf.o v3_extku.o v3_ia5.o v3_lib.o \
 v3_prn.o v3_utl.o v3err.o v3_genn.o v3_alt.o v3_skey.o v3_akey.o v3_pku.o \
 v3_int.o v3_enum.o v3_sxnet.o v3_cpols.o v3_crld.o v3_purp.o v3_info.o \
 v3_akeya.o v3_pmaps.o v3_pcons.o v3_ncons.o v3_pcia.o v3_pci.o \
 pcy_cache.o pcy_node.o pcy_data.o pcy_map.o pcy_tree.o pcy_lib.o \
-v3_asid.o v3_addr.o v3_scts.o
+v3_asid.o v3_addr.o v3_scts.o v3_tlsf.o
 
 SRC= $(LIBSRC)
 
@@ -534,6 +534,20 @@ v3_sxnet.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
 v3_sxnet.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
 v3_sxnet.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
 v3_sxnet.o: ../include/internal/cryptlib.h ext_dat.h v3_sxnet.c
+v3_tlsf.o: ../../e_os.h ../../include/internal/o_str.h
+v3_tlsf.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h
+v3_tlsf.o: ../../include/openssl/bio.h ../../include/openssl/buffer.h
+v3_tlsf.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h
+v3_tlsf.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h
+v3_tlsf.o: ../../include/openssl/err.h ../../include/openssl/evp.h
+v3_tlsf.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h
+v3_tlsf.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
+v3_tlsf.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h
+v3_tlsf.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h
+v3_tlsf.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
+v3_tlsf.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h
+v3_tlsf.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h
+v3_tlsf.o: ../include/internal/cryptlib.h ext_dat.h v3_tlsf.c
 v3_utl.o: ../../e_os.h ../../include/openssl/asn1.h ../../include/openssl/bio.h
 v3_utl.o: ../../include/openssl/bn.h ../../include/openssl/buffer.h
 v3_utl.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h
index c1ddedbfab757fce1a7e29efc710cc4bcb8088b5..3f9f7f3efc51613f200f7298a3254e5ef3be6acd 100644 (file)
@@ -70,3 +70,4 @@ extern const X509V3_EXT_METHOD v3_policy_mappings, v3_policy_constraints;
 extern const X509V3_EXT_METHOD v3_name_constraints, v3_inhibit_anyp, v3_idp;
 extern const X509V3_EXT_METHOD v3_addr, v3_asid;
 extern const X509V3_EXT_METHOD v3_ct_scts[];
+extern const X509V3_EXT_METHOD v3_tls_feature;
index 8d42147f5584f0a516c4f234182b1f124e845d3c..e3cd2ae5ee56175014e97098d17a93fbbfd966dc 100644 (file)
@@ -156,6 +156,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = {
     &v3_ct_scts[0],
     &v3_ct_scts[1],
 #endif
+    &v3_tls_feature,
 };
 
 /* Number of standard extensions */
diff --git a/crypto/x509v3/v3_tlsf.c b/crypto/x509v3/v3_tlsf.c
new file mode 100644 (file)
index 0000000..700546f
--- /dev/null
@@ -0,0 +1,186 @@
+/* v3_tlsf.c */
+/*
+ * Written by Rob Stradling (rob@comodo.com) for the OpenSSL project 2015.
+ */
+/* ====================================================================
+ * Copyright (c) 2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "internal/cryptlib.h"
+#include "internal/o_str.h"
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+#include "ext_dat.h"
+
+static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+                                             TLS_FEATURE *tls_feature,
+                                             STACK_OF(CONF_VALUE) *ext_list);
+static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+                                    X509V3_CTX *ctx,
+                                    STACK_OF(CONF_VALUE) *nval);
+
+ASN1_ITEM_TEMPLATE(TLS_FEATURE) =
+        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, TLS_FEATURE, ASN1_INTEGER)
+static_ASN1_ITEM_TEMPLATE_END(TLS_FEATURE)
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(TLS_FEATURE)
+
+const X509V3_EXT_METHOD v3_tls_feature = {
+    NID_tlsfeature, 0,
+    ASN1_ITEM_ref(TLS_FEATURE),
+    0, 0, 0, 0,
+    0, 0,
+    (X509V3_EXT_I2V)i2v_TLS_FEATURE,
+    (X509V3_EXT_V2I)v2i_TLS_FEATURE,
+    0, 0,
+    NULL
+};
+
+
+typedef struct {
+    long num;
+    const char *name;
+} TLS_FEATURE_NAME;
+
+static TLS_FEATURE_NAME tls_feature_tbl[] = {
+    { 5, "status_request" },
+    { 17, "status_request_v2" }
+};
+
+/*
+ * i2v_TLS_FEATURE converts the TLS_FEATURE structure tls_feature into the
+ * STACK_OF(CONF_VALUE) structure ext_list. STACK_OF(CONF_VALUE) is the format
+ * used by the CONF library to represent a multi-valued extension.  ext_list is
+ * returned.
+ */
+static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+                                             TLS_FEATURE *tls_feature,
+                                             STACK_OF(CONF_VALUE) *ext_list)
+{
+    int i;
+    size_t j;
+    ASN1_INTEGER *ai;
+    long tlsextid;
+    for (i = 0; i < sk_ASN1_INTEGER_num(tls_feature); i++) {
+        ai = sk_ASN1_INTEGER_value(tls_feature, i);
+        tlsextid = ASN1_INTEGER_get(ai);
+        for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++)
+            if (tlsextid == tls_feature_tbl[j].num)
+                break;
+        if (j < OSSL_NELEM(tls_feature_tbl))
+            X509V3_add_value(NULL, tls_feature_tbl[j].name, &ext_list);
+        else
+            X509V3_add_value_int(NULL, ai, &ext_list);
+    }
+    return ext_list;
+}
+
+/*
+ * v2i_TLS_FEATURE converts the multi-valued extension nval into a TLS_FEATURE
+ * structure, which is returned if the conversion is successful.  In case of
+ * error, NULL is returned.
+ */
+static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method,
+                                    X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+    TLS_FEATURE *tlsf;
+    char *extval, *endptr;
+    ASN1_INTEGER *ai;
+    CONF_VALUE *val;
+    int i;
+    size_t j;
+    long tlsextid;
+
+    if ((tlsf = sk_ASN1_INTEGER_new_null()) == NULL) {
+        X509V3err(X509V3_F_V2I_TLS_FEATURE, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+        val = sk_CONF_VALUE_value(nval, i);
+        if (val->value)
+            extval = val->value;
+        else
+            extval = val->name;
+
+        for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++)
+            if (OPENSSL_strcasecmp(extval, tls_feature_tbl[j].name) == 0)
+                break;
+        if (j < OSSL_NELEM(tls_feature_tbl))
+            tlsextid = tls_feature_tbl[j].num;
+        else {
+            tlsextid = strtol(extval, &endptr, 10);
+            if (((*endptr) != '\0') || (extval == endptr) || (tlsextid < 0) ||
+                (tlsextid > 65535)) {
+                X509V3err(X509V3_F_V2I_TLS_FEATURE, X509V3_R_INVALID_SYNTAX);
+                X509V3_conf_err(val);
+                goto err;
+            }
+        }
+
+        ai = ASN1_INTEGER_new();
+        if (ai == NULL) {
+            X509V3err(X509V3_F_V2I_TLS_FEATURE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        ASN1_INTEGER_set(ai, tlsextid);
+        sk_ASN1_INTEGER_push(tlsf, ai);
+    }
+    return tlsf;
+
+ err:
+    sk_ASN1_INTEGER_pop_free(tlsf, ASN1_INTEGER_free);
+    return NULL;
+}
index f9eb064b5484120fc63f10e5310c99cd69474a69..529346b4806bea52637c7ffb6f11a7ac7427b9ca 100644 (file)
@@ -124,6 +124,7 @@ static ERR_STRING_DATA X509V3_str_functs[] = {
     {ERR_FUNC(X509V3_F_V2I_POLICY_CONSTRAINTS), "v2i_POLICY_CONSTRAINTS"},
     {ERR_FUNC(X509V3_F_V2I_POLICY_MAPPINGS), "v2i_POLICY_MAPPINGS"},
     {ERR_FUNC(X509V3_F_V2I_SUBJECT_ALT), "v2i_subject_alt"},
+    {ERR_FUNC(X509V3_F_V2I_TLS_FEATURE), "v2i_TLS_FEATURE"},
     {ERR_FUNC(X509V3_F_V3_ADDR_VALIDATE_PATH_INTERNAL),
      "v3_addr_validate_path_internal"},
     {ERR_FUNC(X509V3_F_V3_GENERIC_EXTENSION), "v3_generic_extension"},
index e965be64808737230407b3974f0c3fdb4fb6e4a6..c2c710b6c7d6ea874ae3e92f7d6c9b2e1432fbfa 100644 (file)
@@ -399,6 +399,20 @@ Example:
  noCheck = ignored
 
 
+=head2 TLS Feature (aka Must Staple)
+
+This is a multi-valued extension consisting of a list of TLS extension
+identifiers. Each identifier may be a number (0..65535) or a supported name.
+When a TLS client sends a listed extension, the TLS server is expected to
+include that extension in its reply.
+
+The supported names are: B<status_request> and B<status_request_v2>.
+
+Example:
+
+ tlsfeature = status_request
+
+
 =head1 DEPRECATED EXTENSIONS
 
 The following extensions are non standard, Netscape specific and largely
index 82500106cc0c8277f8d3fa26a5bbe070e5fd565d..4b50a10221b3399081ee1c2cb1f9d190ee19ddb7 100644 (file)
@@ -139,6 +139,8 @@ RFC5280.
  Policy Constraints                 NID_policy_constraints
  Inhibit Any Policy                 NID_inhibit_any_policy
 
+ TLS Feature                        NID_tlsfeature
+
 =head2 NETSCAPE CERTIFICATE EXTENSIONS
 
 The following are (largely obsolete) Netscape certificate extensions.
index 060126b56c6a594aa34593d1807289ba32b2f5f2..5f21fd5a329bdff6378fa8162be9ddfe0f2603ff 100644 (file)
 #define NID_proxyCertInfo               663
 #define OBJ_proxyCertInfo               OBJ_id_pe,14L
 
+#define SN_tlsfeature           "tlsfeature"
+#define LN_tlsfeature           "TLS Feature"
+#define NID_tlsfeature          1020
+#define OBJ_tlsfeature          OBJ_id_pe,24L
+
 #define SN_id_qt_cps            "id-qt-cps"
 #define LN_id_qt_cps            "Policy Qualifier CPS"
 #define NID_id_qt_cps           164
index 9a68b7316c2d5c0c52ed050be16eedb590ce9fb9..7932acb9c80a4f1a6d9ed234e4806d9e366154da 100644 (file)
@@ -217,6 +217,8 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS;
 
 typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE;
 
+typedef STACK_OF(ASN1_INTEGER) TLS_FEATURE;
+
 DECLARE_STACK_OF(GENERAL_NAME)
 
 DECLARE_STACK_OF(ACCESS_DESCRIPTION)
@@ -561,6 +563,8 @@ ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
 DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE)
 int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION *a);
 
+DECLARE_ASN1_ALLOC_FUNCTIONS(TLS_FEATURE)
+
 DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
 DECLARE_ASN1_FUNCTIONS(POLICYINFO)
 DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO)
@@ -962,6 +966,7 @@ void ERR_load_X509V3_strings(void);
 # define X509V3_F_V2I_POLICY_CONSTRAINTS                  146
 # define X509V3_F_V2I_POLICY_MAPPINGS                     145
 # define X509V3_F_V2I_SUBJECT_ALT                         154
+# define X509V3_F_V2I_TLS_FEATURE                         165
 # define X509V3_F_V3_ADDR_VALIDATE_PATH_INTERNAL          160
 # define X509V3_F_V3_GENERIC_EXTENSION                    116
 # define X509V3_F_X509V3_ADD1_I2D                         140
index 3318a7eb986affe6dc481640d979b0ed960ae878..b02248b4c3aded95034dd9ce28dbe8def9b352bf 100755 (executable)
@@ -4727,3 +4727,5 @@ Poly1305_Update                         5086      EXIST::FUNCTION:POLY1305
 Poly1305_Final                          5087   EXIST::FUNCTION:POLY1305
 EVP_chacha20_poly1305                   5088   EXIST::FUNCTION:CHACHA,POLY1305
 EVP_chacha20                            5089   EXIST::FUNCTION:CHACHA
+TLS_FEATURE_free                        5093   EXIST::FUNCTION:
+TLS_FEATURE_new                         5094   EXIST::FUNCTION: