First draft of CT documentation

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
This commit is contained in:
Rob Percival 2016-04-28 07:37:24 +01:00 committed by Matt Caswell
parent c42b8a6e4b
commit 56f3f714ef
13 changed files with 679 additions and 15 deletions

View file

@ -0,0 +1,45 @@
=pod
=head1 NAME
CTLOG_STORE_get0_log_by_id -
Get a Certificate Transparency log from a CTLOG_STORE
=head1 SYNOPSIS
#include <openssl/ct.h>
const CTLOG *CTLOG_STORE_get0_log_by_id(const CTLOG_STORE *store,
const uint8_t *log_id,
size_t log_id_len);
=head1 DESCRIPTION
A Signed Certificate Timestamp (SCT) identifies the Certificate Transparency
(CT) log that issued it using the log's LogID (see RFC 6962, Section 3.2).
Therefore, it is useful to be able to look up more information about a log
(e.g. its public key) using this LogID.
B<CTLOG_STORE_get0_log_by_id>() provides a way to do this. It will find a CTLOG
in a CTLOG_STORE that has a given LogID.
=head1 RETURN VALUES
B<CTLOG_STORE_get0_log_by_id> returns a CTLOG with the given LogID, if it
exists in the given CTLOG_STORE, otherwise it returns NULL.
=head1 SEE ALSO
L<ct(3)>,
L<CTLOG_STORE_new(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -0,0 +1,75 @@
=pod
=head1 NAME
CTLOG_STORE_new, CTLOG_STORE_free,
CTLOG_STORE_load_default_file, CTLOG_STORE_load_file -
Create and populate a Certificate Transparency log list
=head1 SYNOPSIS
#include <openssl/ct.h>
CTLOG_STORE *CTLOG_STORE_new(void);
void CTLOG_STORE_free(CTLOG_STORE *store);
int CTLOG_STORE_load_default_file(CTLOG_STORE *store);
int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file);
=head1 DESCRIPTION
A CTLOG_STORE is a container for a list of CTLOGs (Certificate Transparency
logs). The list can be loaded from one or more files and then searched by LogID
(see RFC 6962, Section 3.2, for the definition of a LogID).
B<CTLOG_STORE_new>() creates an empty list of CT logs. This is then populated
by B<CTLOG_STORE_load_default_file>() or B<CTLOG_STORE_load_file>().
B<CTLOG_STORE_load_default_file>() loads from the default file, which is named
"ct_log_list.cnf" in the OpenSSL install directory. This can be overridden using
an environment variable named "CTLOG_FILE".
B<CTLOG_STORE_load_file>() loads from a caller-specified file path instead.
Both of these functions append any loaded CT logs to the CTLOG_STORE.
The expected format of the file is:
enabled_logs=foo,bar
[foo]
description = Log 1
key = <base64-encoded public key here>
[bar]
description = Log 2
key = <base64-encoded public key here>
Once a CTLOG_STORE is no longer required, it should be passed to
B<CTLOG_STORE_free>(). This will delete all of the CTLOGs stored within, along
with the CTLOG_STORE itself.
=head1 NOTES
If there are any invalid CT logs in a file, they are skipped and the remaining
valid logs will still be added to the CTLOG_STORE. A CT log will be considered
invalid if it is missing a "key" or "description" field.
=head1 RETURN VALUES
Both B<CTLOG_STORE_load_default_file> and B<CTLOG_STORE_load_file> return 1 if
all CT logs in the file are successfully parsed and loaded, 0 otherwise.
=head1 SEE ALSO
L<ct(3)>,
L<CTLOG_STORE_get0_log_by_id(3)>,
L<SSL_CTX_set_ctlog_list_file(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

47
doc/crypto/CTLOG_new.pod Normal file
View file

@ -0,0 +1,47 @@
=pod
=head1 NAME
Func -
title
=head1 SYNOPSIS
#include <openssl/ct.h>
CTLOG *CTLOG_new(EVP_PKEY *public_key, const char *name);
CTLOG *CTLOG_new_null(void);
int CTLOG_new_from_base64(CTLOG ** ct_log,
const char *pkey_base64, const char *name);
void CTLOG_free(CTLOG *log);
const char *CTLOG_get0_name(const CTLOG *log);
void CTLOG_get0_log_id(const CTLOG *log, const uint8_t **log_id,
size_t *log_id_len);
EVP_PKEY *CTLOG_get0_public_key(const CTLOG *log);
=head1 DESCRIPTION
=head1 NOTES
=head1 RETURN VALUES
=head1 SEE ALSO
L<ct(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -0,0 +1,84 @@
=pod
=head1 NAME
CT_POLICY_EVAL_CTX -
Encapsulates the data required to evaluate whether SCTs meet a Certificate Transparency policy
=head1 SYNOPSIS
#include <openssl/ct.h>
CT_POLICY_EVAL_CTX *CT_POLICY_EVAL_CTX_new(void);
void CT_POLICY_EVAL_CTX_free(CT_POLICY_EVAL_CTX *ctx);
X509* CT_POLICY_EVAL_CTX_get0_cert(const CT_POLICY_EVAL_CTX *ctx);
void CT_POLICY_EVAL_CTX_set0_cert(CT_POLICY_EVAL_CTX *ctx, X509 *cert);
X509* CT_POLICY_EVAL_CTX_get0_issuer(const CT_POLICY_EVAL_CTX *ctx);
void CT_POLICY_EVAL_CTX_set0_issuer(CT_POLICY_EVAL_CTX *ctx, X509 *issuer);
const CTLOG_STORE *CT_POLICY_EVAL_CTX_get0_log_store(const CT_POLICY_EVAL_CTX *ctx);
void CT_POLICY_EVAL_CTX_set0_log_store(CT_POLICY_EVAL_CTX *ctx, CTLOG_STORE *log_store);
=head1 DESCRIPTION
A B<CT_POLICY_EVAL_CTX> is used by functions that evaluate whether Signed
Certificate Timestamps (SCTs) fulfil a Certificate Transparency (CT) policy.
This policy may be, for example, that at least one valid SCT is available. To
determine this, an SCT's signature must be verified. This requires:
=over
=item * the public key of the log that issued the SCT
=item * the certificate that the SCT was issued for
=item * the issuer certificate (if the SCT was issued for a pre-certificate)
=back
The above requirements are met using the setters described below.
B<CT_POLICY_EVAL_CTX_new>() creates an empty policy evaluation context. This
should then be populated using:
=over
=item * B<CT_POLICY_EVAL_CTX_set0_cert>() to provide the certificate the SCTs were issued for
=item * B<CT_POLICY_EVAL_CTX_set0_issuer>() to provide the issuer certificate
=item * B<CT_POLICY_EVAL_CTX_set0_log_store>() to provide a list of logs that are trusted as sources of SCTs
=back
None of these setters take ownership of the pointers passed to them.
Each setter has a matching getter for accessing the current value.
The getters do not transfer ownership either.
When no longer required, the B<CT_POLICY_EVAL_CTX> should be passed to
B<CT_POLICY_EVAL_CTX_free>() to delete it.
=head1 NOTES
The issuer certificate only needs to be provided if at least one of the SCTs
was issued for a pre-certificate. This will be the case for SCTs embedded in a
certificate (i.e. those in an X.509 extension), but may not be the case for SCTs
found in the TLS SCT extension or OCSP response.
=head1 RETURN VALUES
B<CT_POLICY_EVAL_CTX_new>() will return NULL if malloc fails.
=head1 SEE ALSO
L<ct(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

163
doc/crypto/SCT_new.pod Normal file
View file

@ -0,0 +1,163 @@
=pod
=head1 NAME
SCT - A Certificate Transparency Signed Certificate Timestamp
=head1 SYNOPSIS
#include <openssl/ct.h>
SCT *SCT_new(void);
SCT *SCT_new_from_base64(unsigned char version,
const char *logid_base64,
ct_log_entry_type_t entry_type,
uint64_t timestamp,
const char *extensions_base64,
const char *signature_base64);
void SCT_free(SCT *sct);
void SCT_LIST_free(STACK_OF(SCT) *a);
sct_version_t SCT_get_version(const SCT *sct);
int SCT_set_version(SCT *sct, sct_version_t version);
ct_log_entry_type_t SCT_get_log_entry_type(const SCT *sct);
int SCT_set_log_entry_type(SCT *sct, ct_log_entry_type_t entry_type);
size_t SCT_get0_log_id(const SCT *sct, unsigned char **log_id);
int SCT_set0_log_id(SCT *sct, unsigned char *log_id, size_t log_id_len);
int SCT_set1_log_id(SCT *sct, const unsigned char *log_id, size_t log_id_len);
uint64_t SCT_get_timestamp(const SCT *sct);
void SCT_set_timestamp(SCT *sct, uint64_t timestamp);
int SCT_get_signature_nid(const SCT *sct);
int SCT_set_signature_nid(SCT *sct, int nid);
size_t SCT_get0_extensions(const SCT *sct, unsigned char **ext);
void SCT_set0_extensions(SCT *sct, unsigned char *ext, size_t ext_len);
int SCT_set1_extensions(SCT *sct, const unsigned char *ext, size_t ext_len);
size_t SCT_get0_signature(const SCT *sct, unsigned char **sig);
void SCT_set0_signature(SCT *sct, unsigned char *sig, size_t sig_len);
int SCT_set1_signature(SCT *sct, const unsigned char *sig, size_t sig_len);
sct_source_t SCT_get_source(const SCT *sct);
int SCT_set_source(SCT *sct, sct_source_t source);
=head1 DESCRIPTION
Signed Certificate Timestamps (SCTs) are defined by RFC 6962, Section 3.2.
They constitute a promise by a Certificate Transparency (CT) log to publicly
record a certificate. By cryptographically verifying that a log did indeed issue
an SCT, some confidence can be gained that the certificate is publicly known.
An internal representation of an SCT can be created in one of two ways.
The first option is to create a blank SCT, using B<SCT_new>(), and then populate
it using:
=over
=item * B<SCT_set_version>() to set the SCT version.
Only SCT_VERSION_V1 is currently supported.
=item * B<SCT_set_log_entry_type>() to set the type of certificate the SCT was issued for:
B<CT_LOG_ENTRY_TYPE_X509> for a normal certificate.
B<CT_LOG_ENTRY_TYPE_PRECERT> for a pre-certificate.
=item * B<SCT_set0_log_id>() or B<SCT_set1_log_id>() to set the LogID of the CT log that the SCT came from.
The former takes ownership, whereas the latter makes a copy.
See RFC 6962, Section 3.2 for the definition of LogID.
=item * B<SCT_set_timestamp>() to set the time the SCT was issued (epoch time in milliseconds).
=item * B<SCT_set_signature_nid>() to set the NID of the signature.
=item * B<SCT_set0_signature>() or B<SCT_set1_signature>() to set the signature itself.
The former takes ownership, whereas the latter makes a copy.
=item * B<SCT_set0_extensions>() or B<SCT_set1_extensions> to provide SCT extensions.
The former takes ownership, whereas the latter makes a copy.
=back
Alternatively, the SCT can be pre-populated from the following data using
B<SCT_new_from_base64>():
=over
=item * The SCT version (only SCT_VERSION_V1 is currently supported).
=item * The LogID (see RFC 6962, Section 3.2), base64 encoded.
=item * The type of certificate the SCT was issued for:
B<CT_LOG_ENTRY_TYPE_X509> for a normal certificate.
B<CT_LOG_ENTRY_TYPE_PRECERT> for a pre-certificate.
=item * The time that the SCT was issued (epoch time in milliseconds).
=item * The SCT extensions, base64 encoded.
=item * The SCT signature, base64 encoded.
=back
B<SCT_set_source>() can be used to record where the SCT was found
(TLS extension, X.509 certificate extension or OCSP response). This is not
required for verifying the SCT.
=head1 NOTES
Some of the setters return int, instead of void. These will all return 1 on
success, 0 on failure. They will not make changes on failure.
Most of the setters will reset the validation status of the SCT to
SCT_VALIDATION_STATUS_NOT_SET (see L<SCT_verify(3)>).
B<SCT_set_source>() will call B<SCT_set_log_entry_type>() if the type of
certificate the SCT was issued for can be inferred from where the SCT was found.
For example, an SCT found in an X.509 extension must have been issued for a pre-
certificate.
B<SCT_set_source>() will not refuse unknown values.
=head1 RETURN VALUES
B<SCT_set_version>() returns 1 if the specified version is supported, 0 otherwise.
B<SCT_set_log_entry_type>() returns 1 if the specified log entry type is supported, 0 otherwise.
B<SCT_set0_log_id>() and B<SCT_set1_log_id> return 1 if the specified LogID is a
valid SHA-256 hash, 0 otherwise. Aditionally, B<SCT_set1_log_id> returns 0 if
malloc fails.
B<SCT_set_signature_nid> returns 1 if the specified NID is supported, 0 otherwise.
B<SCT_set1_extensions> and B<SCT_set1_signature> return 1 if the supplied buffer
is copied successfully, 0 otherwise (i.e. if malloc fails).
B<SCT_set_source> will always return 1.
=head1 SEE ALSO
L<ct(3)>,
L<SCT_verify(3)>,
L<OBJ_nid2obj(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

48
doc/crypto/SCT_print.pod Normal file
View file

@ -0,0 +1,48 @@
=pod
=head1 NAME
SCT_print, SCL_LIST_print, SCT_validation_status_string -
Prints Signed Certificate Timestamps in a human-readable way
=head1 SYNOPSIS
#include <openssl/ct.h>
void SCT_print(const SCT *sct, BIO *out, int indent, const CTLOG_STORE *logs);
void SCT_LIST_print(const STACK_OF(SCT) *sct_list, BIO *out, int indent,
const char *separator, const CTLOG_STORE *logs);
const char *SCT_validation_status_string(const SCT *sct);
=head1 DESCRIPTION
B<SCT_print> prints a single Signed Certificate Timestamp (SCT) to a L<bio> in
a human-readable format. B<SCT_LIST_print> prints an entire list of SCTs in a
similar way. A separator can be specified to delimit each SCT in the output.
The output can be indented by a specified number of spaces. If a B<CTLOG_STORE>
is provided, it will be used to print the description of the CT log that issued
each SCT (if that log is in the CTLOG_STORE). Alternatively, NULL can be passed
as the CTLOG_STORE parameter to disable this feature.
B<SCT_validation_status_string> will return the validation status of an SCT as
a human-readable string. Call L<SCT_validate> or B<SCT_LIST_validate> beforehand
in order to set the validation status of an SCT first.
=head1 SEE ALSO
L<ct(3)>,
L<bio(3)>,
L<CTLOG_STORE_new(3)>,
L<SCT_validate(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -0,0 +1,41 @@
=pod
=head1 NAME
SCT_validate, SCT_LIST_validate, SCT_get_validation_status -
checks Signed Certificate Timestamps meet a Certificate Transparency policy
=head1 SYNOPSIS
#include <openssl/ct.h>
sct_validation_status_t SCT_get_validation_status(const SCT *sct);
int SCT_validate(SCT *sct, const CT_POLICY_EVAL_CTX *ctx);
int SCT_LIST_validate(const STACK_OF(SCT) *scts, CT_POLICY_EVAL_CTX *ctx);
=head1 DESCRIPTION
=head1 NOTES
=head1 RETURN VALUES
=head1 SEE ALSO
L<ct(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

40
doc/crypto/SCT_verify.pod Normal file
View file

@ -0,0 +1,40 @@
=pod
=head1 NAME
SCT_verify, SCT_verify_v1 -
verifies a Signed Certificate Timestamp's signature
=head1 SYNOPSIS
#include <openssl/ct.h>
int SCT_verify(const SCT_CTX *sctx, const SCT *sct);
int SCT_verify_v1(SCT *sct, X509 *cert, X509 *preissuer, X509_PUBKEY *log_pubkey, X509 *issuer_cert);
=head1 DESCRIPTION
=head1 NOTES
=head1 RETURN VALUES
=head1 SEE ALSO
L<ct(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

40
doc/crypto/ct.pod Normal file
View file

@ -0,0 +1,40 @@
=pod
=head1 NAME
ct - Certificate Transparency
=head1 SYNOPSIS
#include <openssl/ct.h>
=head1 DESCRIPTION
This library implements Certificate Transparency (CT) verification for TLS
clients, as defined in RFC 6962. This verification can provide some confidence
that a certificate has been publicly logged in a set of CT logs.
By default, these checks are disabled. They can be enabled using
B<SSL_CTX_ct_enable>() or B<SSL_ct_enable>().
This library can also be used to parse and examine CT data structures, such as
Signed Certificate Timestamps (SCTs), or to read a list of CT logs. There are
functions for:
- decoding and encoding SCTs in DER and TLS wire format.
- printing SCTs.
- verifying the authenticity of SCTs.
- loading a CT log list from a CONF file.
=head1 SEE ALSO
L<d2i_SCT_LIST(3)>,
L<CTLOG_STORE_new(3)>,
L<CTLOG_STORE_get0_log_by_id(3),
L<SCT_new(3)>,
L<SCT_print(3)>,
L<SCT_verify(3)>,
L<SCT_validate(3)>,
L<CT_POLICY_EVAL_CTX(3)>,
L<SSL_CTX_set_ct_validation_callback(3)>
=cut

View file

@ -0,0 +1,41 @@
=pod
=head1 NAME
d2i_SCT_LIST, i2d_SCT_LIST -
decode and encode Signed Certificate Timestamp lists in DER format
=head1 SYNOPSIS
#include <openssl/ct.h>
STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp, long len);
int i2d_SCT_LIST(const STACK_OF(SCT) *a, unsigned char **pp);
=head1 DESCRIPTION
=head1 NOTES
=head1 RETURN VALUES
=head1 SEE ALSO
L<ct(3)>,
L(o2i_SCT_LIST(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -0,0 +1,45 @@
=pod
=head1 NAME
o2i_SCT_LIST, i2o_SCT_LIST, o2i_SCT, i2o_SCT, o2i_SCT_signature, i2o_SCT_signature -
decode and encode Signed Certificate Timestamp lists in TLS wire format
=head1 SYNOPSIS
#include <openssl/ct.h>
STACK_OF(SCT) *o2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp, size_t len);
int i2o_SCT_LIST(const STACK_OF(SCT) *a, unsigned char **pp);
SCT *o2i_SCT(SCT **psct, const unsigned char **in, size_t len);
int i2o_SCT(const SCT *sct, unsigned char **out);
int o2i_SCT_signature(SCT *sct, const unsigned char **in, size_t len);
int i2o_SCT_signature(const SCT *sct, unsigned char **out);
=head1 DESCRIPTION
=head1 NOTES
=head1 RETURN VALUES
=head1 SEE ALSO
L<ct(3)>,
L(d2i_SCT_LIST(3)>
=head1 COPYRIGHT
Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the OpenSSL license (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -18,24 +18,13 @@ SSL_CTX_set_default_ctlog_list_file() loads a list of Certificate Transparency
(CT) logs from the default file location, "ct_log_list.cnf", found in the
directory where OpenSSL is installed.
SSL_CTX_set_ctlog_list_file() loads a list of CT logs from a given path.
The expected format of the log list file is:
enabled_logs=foo,bar
[foo]
description = Log 1
key = <base64-encoded public key here>
[bar]
description = Log 2
key = <base64-encoded public key here>
SSL_CTX_set_ctlog_list_file() loads a list of CT logs from a specific path.
See L<CTLOG_STORE_new(3)> for the file format.
=head1 NOTES
These functions will not clear the existing CT log list - it will be appended
to.
to. To replace the existing list, use L<SSL_CTX_set0_ctlog_store> first.
If an error occurs whilst parsing a particular log entry in the file, that log
entry will be skipped.
@ -49,7 +38,8 @@ the case of an error, the log list may have been partially loaded.
=head1 SEE ALSO
L<ssl(3)>,
L<ssl_ct_validation_cb(3)>
L<SSL_CTX_set_ct_validation_callback(3)>,
L<CTLOG_STORE_new(3)>
=head1 COPYRIGHT

View file

@ -330,6 +330,8 @@ protocol context defined in the B<SSL_CTX> structure.
=item void B<SSL_CTX_set_client_cert_cb>(SSL_CTX *ctx, int (*cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey));
=item int B<SSL_CTX_set_ct_validation_callback>(SSL_CTX *ctx, ssl_ct_validation_cb callback, void *arg);
=item void B<SSL_CTX_set_default_passwd_cb>(SSL_CTX *ctx, int (*cb);(void))
=item void B<SSL_CTX_set_default_read_ahead>(SSL_CTX *ctx, int m);
@ -630,6 +632,8 @@ fresh handle for each connection.
=item void B<SSL_set_connect_state>(SSL *ssl);
=item int B<SSL_set_ct_validation_callback>(SSL *ssl, ssl_ct_validation_cb callback, void *arg);
=item int B<SSL_set_ex_data>(SSL *ssl, int idx, char *arg);
=item int B<SSL_set_fd>(SSL *ssl, int fd);
@ -770,6 +774,7 @@ L<SSL_CTX_set_verify(3)>,
L<SSL_CTX_use_certificate(3)>,
L<SSL_alert_type_string(3)>,
L<SSL_do_handshake(3)>,
L<SSL_enable_ct(3)>,
L<SSL_get_SSL_CTX(3)>,
L<SSL_get_ciphers(3)>,
L<SSL_get_client_CA_list(3)>,