From 052cf77233172959ec928d071e8b572ecdd5b883 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 8 Oct 2024 16:11:46 -0500 Subject: [PATCH 1/5] acert: fix defines, cleanup, more testing. --- src/x509.c | 756 ++++++++++++++++++--------------- tests/api.c | 148 +++++++ wolfcrypt/src/asn.c | 25 ++ wolfssl/internal.h | 3 +- wolfssl/ssl.h | 21 +- wolfssl/wolfcrypt/asn.h | 1 - wolfssl/wolfcrypt/asn_public.h | 13 + 7 files changed, 613 insertions(+), 354 deletions(-) diff --git a/src/x509.c b/src/x509.c index 72563c4e6..91b305322 100644 --- a/src/x509.c +++ b/src/x509.c @@ -6049,25 +6049,6 @@ static int X509_ACERT_print_name_entry(WOLFSSL_BIO* bio, return ret; } -/* Sets buf pointer and len to raw Attribute buffer and buffer len - * in X509 struct. - * - * Returns WOLFSSL_SUCCESS on success. - * Returns BAD_FUNC_ARG if input pointers are null. - * */ -WOLFSSL_API int wolfSSL_X509_ACERT_get_attr_buf(const WOLFSSL_X509_ACERT* x509, - const byte ** rawAttr, - word32 * rawAttrLen) -{ - if (x509 == NULL || rawAttr == NULL || rawAttrLen == NULL) { - return BAD_FUNC_ARG; - } - - *rawAttr = x509->rawAttr; - *rawAttrLen = x509->rawAttrLen; - - return WOLFSSL_SUCCESS; -} #endif /* if WOLFSSL_ACERT*/ static int X509PrintSubjAltName(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, @@ -7220,168 +7201,6 @@ int wolfSSL_X509_print(WOLFSSL_BIO* bio, WOLFSSL_X509* x509) } #if defined(WOLFSSL_ACERT) -WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_load_certificate_buffer( - const unsigned char* buf, int sz, int format) -{ - int ret = 0; - WOLFSSL_X509_ACERT * x509 = NULL; - DerBuffer * der = NULL; - #ifdef WOLFSSL_SMALL_STACK - DecodedAcert * acert = NULL; - #else - DecodedAcert acert[1]; - #endif - - WOLFSSL_ENTER("wolfSSL_X509_ACERT_load_certificate_buffer"); - - if (format == WOLFSSL_FILETYPE_PEM) { - #ifdef WOLFSSL_PEM_TO_DER - ret = PemToDer(buf, sz, ACERT_TYPE, &der, NULL, NULL, NULL); - - if (ret != 0 || der == NULL || der->buffer == NULL) { - WOLFSSL_ERROR(ret); - - if (der != NULL) { - FreeDer(&der); - } - - return NULL; - } - #else - WOLFSSL_ERROR(NOT_COMPILED_IN); - return NULL; - #endif - } - else { - ret = AllocDer(&der, (word32)sz, ACERT_TYPE, NULL); - - if (ret != 0 || der == NULL || der->buffer == NULL) { - WOLFSSL_ERROR(ret); - return NULL; - } - - XMEMCPY(der->buffer, buf, sz); - } - - #ifdef WOLFSSL_SMALL_STACK - acert = (DecodedAcert*)XMALLOC(sizeof(DecodedAcert), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (acert == NULL) { - WOLFSSL_ERROR(MEMORY_ERROR); - FreeDer(&der); - return NULL; - } - #endif - - InitDecodedAcert(acert, der->buffer, der->length, NULL); - - ret = ParseX509Acert(acert, VERIFY_SKIP_DATE); - - if (ret == 0) { - x509 = (WOLFSSL_X509_ACERT*)XMALLOC(sizeof(WOLFSSL_X509_ACERT), NULL, - DYNAMIC_TYPE_X509_ACERT); - if (x509 != NULL) { - wolfSSL_X509_ACERT_init(x509, NULL); - ret = CopyDecodedAcertToX509(x509, acert); - - if (ret != 0) { - wolfSSL_X509_ACERT_free(x509); - x509 = NULL; - } - } - else { - ret = MEMORY_ERROR; - } - } - - FreeDecodedAcert(acert); - - #ifdef WOLFSSL_SMALL_STACK - XFREE(acert, NULL, DYNAMIC_TYPE_DCERT); - #endif - - FreeDer(&der); - - if (ret != 0) { - WOLFSSL_ERROR(ret); - } - - return x509; -} - -void wolfSSL_X509_ACERT_init(WOLFSSL_X509_ACERT * x509, void* heap) -{ - if (x509 == NULL) { - WOLFSSL_MSG("error: InitX509Acert: null parameter"); - return; - } - - XMEMSET(x509, 0, sizeof(*x509)); - - x509->heap = heap; -} - -void wolfSSL_X509_ACERT_free(WOLFSSL_X509_ACERT* x509) -{ - if (x509 == NULL) { - WOLFSSL_MSG("error: wolfSSL_X509_ACERT_free: null parameter"); - return; - } - - /* Free holder and att cert issuer structures. */ - if (x509->holderIssuerName) { - FreeAltNames(x509->holderIssuerName, x509->heap); - x509->holderIssuerName = NULL; - } - - if (x509->AttCertIssuerName) { - FreeAltNames(x509->AttCertIssuerName, x509->heap); - x509->AttCertIssuerName = NULL; - } - - if (x509->rawAttr != NULL) { - XFREE(x509->rawAttr, x509->heap, DYNAMIC_TYPE_X509_EXT); - x509->rawAttr = NULL; - x509->rawAttrLen = 0; - } - - /* Free derCert source and signature buffer. */ - FreeDer(&x509->derCert); - - if (x509->sig.buffer != NULL) { - XFREE(x509->sig.buffer, x509->heap, DYNAMIC_TYPE_SIGNATURE); - x509->sig.buffer = NULL; - } - - /* Finally memset and free x509 acert structure. */ - XMEMSET(x509, 0, sizeof(*x509)); - XFREE(x509, NULL, DYNAMIC_TYPE_X509_ACERT); - - return; -} - -long wolfSSL_X509_ACERT_get_version(const WOLFSSL_X509_ACERT* x509) -{ - int version = 0; - - if (x509 == NULL) { - return 0L; - } - - version = x509->version; - - return version != 0 ? (long)version - 1L : 0L; -} - -int wolfSSL_X509_ACERT_version(WOLFSSL_X509_ACERT* x509) -{ - if (x509 == NULL) { - return 0; - } - - return x509->version; -} - /* Retrieve sig NID from an ACERT. * * returns NID on success @@ -7396,43 +7215,6 @@ int wolfSSL_X509_ACERT_get_signature_nid(const WOLFSSL_X509_ACERT *x509) return oid2nid((word32)x509->sigOID, oidSigType); } -/* Retrieve the signature from an ACERT. - * - * @param [in] x509 the x509 attribute certificate - * @param [in, out] buf the signature buffer pointer - * @param [in, out] bufSz the signature buffer size pointer - * - * buf may be null, but bufSz is required. On success, sets - * bufSz pointer to signature length, and copies signature - * to buf if provided. - * - * Returns WWOLFSSL_FATAL_ERROR if bufSz is null or too small. - * Returns WOLFSSL_SUCCESS on success. - */ -int wolfSSL_X509_ACERT_get_signature(WOLFSSL_X509_ACERT* x509, - unsigned char* buf, int* bufSz) -{ - WOLFSSL_ENTER("wolfSSL_X509_ACERT_get_signature"); - - if (x509 == NULL || bufSz == NULL) { - return WOLFSSL_FATAL_ERROR; - } - - /* If buf array is provided, it must be long enough. */ - if (buf != NULL && *bufSz < (int)x509->sig.length) { - return WOLFSSL_FATAL_ERROR; - } - - if (buf != NULL) { - /* Copy in buffer if provided. */ - XMEMCPY(buf, x509->sig.buffer, x509->sig.length); - } - - *bufSz = (int)x509->sig.length; - - return WOLFSSL_SUCCESS; -} - static int X509AcertPrintSignature(WOLFSSL_BIO* bio, WOLFSSL_X509_ACERT* x509, int algOnly, int indent) { @@ -7475,43 +7257,6 @@ static int X509AcertPrintSignature(WOLFSSL_BIO* bio, WOLFSSL_X509_ACERT* x509, return WOLFSSL_SUCCESS; } -/* Retrieve the serial number from an ACERT. - * - * @param [in] x509 the x509 attribute certificate - * @param [in, out] buf the serial number buffer pointer - * @param [in, out] bufSz the serial number buffer size pointer - * - * buf may be null, but bufSz is required. On success, sets - * bufSz pointer to signature length, and copies signature - * to buf if provided. - * - * Returns WWOLFSSL_FATAL_ERROR if bufSz is null or too small. - * Returns WOLFSSL_SUCCESS on success. - */ -int wolfSSL_X509_ACERT_get_serial_number(WOLFSSL_X509_ACERT* x509, - byte* buf, int* bufSz) -{ - WOLFSSL_ENTER("wolfSSL_X509_ACERT_get_serial_number"); - - if (x509 == NULL || bufSz == NULL) { - WOLFSSL_MSG("error: null argument passed in"); - return BAD_FUNC_ARG; - } - - if (buf != NULL) { - if (*bufSz < x509->serialSz) { - WOLFSSL_MSG("error: serial buffer too small"); - return BUFFER_E; - } - - XMEMCPY(buf, x509->serial, x509->serialSz); - } - - *bufSz = x509->serialSz; - - return WOLFSSL_SUCCESS; -} - static int X509AcertPrintSerial(WOLFSSL_BIO* bio, WOLFSSL_X509_ACERT* x509, int indent) { @@ -8385,95 +8130,6 @@ int wolfSSL_X509_REQ_verify(WOLFSSL_X509* x509, WOLFSSL_EVP_PKEY* pkey) } #endif /* WOLFSSL_CERT_REQ */ -#if defined(WOLFSSL_ACERT) - -#ifndef NO_WOLFSSL_STUB -WOLFSSL_API int wolfSSL_X509_ACERT_sign(WOLFSSL_X509_ACERT * x509, - WOLFSSL_EVP_PKEY * pkey, - const WOLFSSL_EVP_MD * md) -{ - WOLFSSL_STUB("X509_ACERT_sign"); - (void) x509; - (void) pkey; - (void) md; - return WOLFSSL_NOT_IMPLEMENTED; -} -#endif /* NO_WOLFSSL_STUB */ - -/* Helper function for ACERT_verify. - * - * @param [in] x509 the x509 attribute certificate - * @param [in, out] outSz the x509 der length - * - * @return der buffer on success - * @return NULL on error - * */ -static const byte* acert_get_der(WOLFSSL_X509_ACERT * x509, int* outSz) -{ - if (x509 == NULL || x509->derCert == NULL || outSz == NULL) { - return NULL; - } - - *outSz = (int)x509->derCert->length; - return x509->derCert->buffer; -} - -/* Given an X509_ACERT and EVP_PKEY, verify the acert's signature. - * - * @param [in] x509 the x509 attribute certificate - * @param [in] pkey the evp_pkey - * - * @return WOLFSSL_SUCCESS on verify success - * @return < 0 on error - * */ -int wolfSSL_X509_ACERT_verify(WOLFSSL_X509_ACERT* x509, WOLFSSL_EVP_PKEY* pkey) -{ - int ret = 0; - const byte * der = NULL; - int derSz = 0; - int pkey_type; - - if (x509 == NULL || pkey == NULL) { - WOLFSSL_MSG("error: wolfSSL_X509_ACERT_verify: bad arg"); - return WOLFSSL_FATAL_ERROR; - } - - WOLFSSL_ENTER("wolfSSL_X509_ACERT_verify"); - - der = acert_get_der(x509, &derSz); - - if (der == NULL || derSz <= 0) { - WOLFSSL_MSG("error: wolfSSL_X509_ACERT_verify: get der failed"); - return WOLFSSL_FATAL_ERROR; - } - - switch (pkey->type) { - case EVP_PKEY_RSA: - pkey_type = RSAk; - break; - - case EVP_PKEY_EC: - pkey_type = ECDSAk; - break; - - case EVP_PKEY_DSA: - pkey_type = DSAk; - break; - - default: - WOLFSSL_MSG("error: wolfSSL_X509_ACERT_verify: unknown pkey type"); - return WOLFSSL_FATAL_ERROR; - } - - - ret = VerifyX509Acert(der, (word32)derSz, - (const byte *)pkey->pkey.ptr, pkey->pkey_sz, - pkey_type, x509->heap); - - return ret == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -#endif /* WOLFSSL_ACERT */ - #if !defined(NO_FILESYSTEM) static void *wolfSSL_d2i_X509_fp_ex(XFILE file, void **x509, int type) { @@ -15588,7 +15244,417 @@ void wolfSSL_X509_ATTRIBUTE_free(WOLFSSL_X509_ATTRIBUTE* attr) XFREE(attr, NULL, DYNAMIC_TYPE_OPENSSL); } } -#endif +#endif /* (OPENSSL_ALL || OPENSSL_EXTRA) && + (WOLFSSL_CERT_GEN || WOLFSSL_CERT_REQ) */ + +#if defined(WOLFSSL_ACERT) && \ + (defined(OPENSSL_EXTRA_X509_SMALL) || defined(OPENSSL_EXTRA)) + +/* Allocate and return a new WOLFSSL_X509_ACERT struct pointer. + * + * @param [in] heap heap hint + * + * @return pointer on success + * @return NULL on error + * */ +WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_new_ex(void* heap) +{ + WOLFSSL_X509_ACERT* x509; + + x509 = (WOLFSSL_X509_ACERT*) XMALLOC(sizeof(WOLFSSL_X509_ACERT), heap, + DYNAMIC_TYPE_X509_ACERT); + + if (x509 != NULL) { + wolfSSL_X509_ACERT_init(x509, 1, heap); + } + + return x509; +} + +WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_new(void) +{ + return wolfSSL_X509_ACERT_new_ex(NULL); +} + +/* Initialize a WOLFSSL_X509_ACERT struct. + * + * If dynamic == 1, then the x509 pointer will be freed + * in wolfSSL_X509_ACERT_free. + * + * @param [in] x509 x509 acert pointer + * @param [in] dynamic dynamic mem flag + * @param [in] heap heap hint + * + * @return void + * */ +void wolfSSL_X509_ACERT_init(WOLFSSL_X509_ACERT * x509, int dynamic, void* heap) +{ + if (x509 == NULL) { + WOLFSSL_MSG("error: InitX509Acert: null parameter"); + return; + } + + XMEMSET(x509, 0, sizeof(*x509)); + + x509->heap = heap; + x509->dynamic = dynamic; +} + +/* Free a WOLFSSL_X509_ACERT struct and its sub-fields. + * + * If this ACERT was initialized with dynamic == 1, then + * the x509 pointer itself will be freed as well. + * + * @param [in] x509 x509 acert pointer + * + * @return void + * */ +void wolfSSL_X509_ACERT_free(WOLFSSL_X509_ACERT * x509) +{ + int dynamic = 0; + void * heap = NULL; + + if (x509 == NULL) { + WOLFSSL_MSG("error: wolfSSL_X509_ACERT_free: null parameter"); + return; + } + + dynamic = x509->dynamic; + heap = x509->heap; + + /* Free holder and att cert issuer structures. */ + if (x509->holderIssuerName) { + FreeAltNames(x509->holderIssuerName, heap); + x509->holderIssuerName = NULL; + } + + if (x509->AttCertIssuerName) { + FreeAltNames(x509->AttCertIssuerName, heap); + x509->AttCertIssuerName = NULL; + } + + if (x509->rawAttr != NULL) { + XFREE(x509->rawAttr, heap, DYNAMIC_TYPE_X509_EXT); + x509->rawAttr = NULL; + x509->rawAttrLen = 0; + } + + /* Free derCert source and signature buffer. */ + FreeDer(&x509->derCert); + + if (x509->sig.buffer != NULL) { + XFREE(x509->sig.buffer, heap, DYNAMIC_TYPE_SIGNATURE); + x509->sig.buffer = NULL; + } + + /* Finally memset and free x509 acert structure. */ + XMEMSET(x509, 0, sizeof(*x509)); + + if (dynamic == 1) { + XFREE(x509, heap, DYNAMIC_TYPE_X509_ACERT); + } + + return; +} + +#if defined(OPENSSL_EXTRA) +long wolfSSL_X509_ACERT_get_version(const WOLFSSL_X509_ACERT* x509) +{ + int version = 0; + + if (x509 == NULL) { + return 0L; + } + + version = x509->version; + + return version != 0 ? (long)version - 1L : 0L; +} +#endif /* OPENSSL_EXTRA */ + +int wolfSSL_X509_ACERT_version(WOLFSSL_X509_ACERT* x509) +{ + if (x509 == NULL) { + return 0; + } + + return x509->version; +} + +/* Retrieve the serial number from an ACERT. + * + * @param [in] x509 the x509 attribute certificate + * @param [in, out] buf the serial number buffer pointer + * @param [in, out] bufSz the serial number buffer size pointer + * + * buf may be null, but bufSz is required. On success, sets + * bufSz pointer to signature length, and copies signature + * to buf if provided. + * + * Returns WWOLFSSL_FATAL_ERROR if bufSz is null or too small. + * Returns WOLFSSL_SUCCESS on success. + */ +int wolfSSL_X509_ACERT_get_serial_number(WOLFSSL_X509_ACERT* x509, + byte* buf, int* bufSz) +{ + WOLFSSL_ENTER("wolfSSL_X509_ACERT_get_serial_number"); + + if (x509 == NULL || bufSz == NULL) { + WOLFSSL_MSG("error: null argument passed in"); + return BAD_FUNC_ARG; + } + + if (buf != NULL) { + if (*bufSz < x509->serialSz) { + WOLFSSL_MSG("error: serial buffer too small"); + return BUFFER_E; + } + + XMEMCPY(buf, x509->serial, x509->serialSz); + } + + *bufSz = x509->serialSz; + + return WOLFSSL_SUCCESS; +} + +/* Sets buf pointer and len to raw Attribute buffer and buffer len + * in X509 struct. + * + * Returns WOLFSSL_SUCCESS on success. + * Returns BAD_FUNC_ARG if input pointers are null. + * */ +WOLFSSL_API int wolfSSL_X509_ACERT_get_attr_buf(const WOLFSSL_X509_ACERT* x509, + const byte ** rawAttr, + word32 * rawAttrLen) +{ + if (x509 == NULL || rawAttr == NULL || rawAttrLen == NULL) { + return BAD_FUNC_ARG; + } + + *rawAttr = x509->rawAttr; + *rawAttrLen = x509->rawAttrLen; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_WOLFSSL_STUB +WOLFSSL_API int wolfSSL_X509_ACERT_sign(WOLFSSL_X509_ACERT * x509, + WOLFSSL_EVP_PKEY * pkey, + const WOLFSSL_EVP_MD * md) +{ + WOLFSSL_STUB("X509_ACERT_sign"); + (void) x509; + (void) pkey; + (void) md; + return WOLFSSL_NOT_IMPLEMENTED; +} +#endif /* NO_WOLFSSL_STUB */ + +/* Helper function for ACERT_verify. + * + * @param [in] x509 the x509 attribute certificate + * @param [in, out] outSz the x509 der length + * + * @return der buffer on success + * @return NULL on error + * */ +static const byte* acert_get_der(WOLFSSL_X509_ACERT * x509, int* outSz) +{ + if (x509 == NULL || x509->derCert == NULL || outSz == NULL) { + return NULL; + } + + *outSz = (int)x509->derCert->length; + return x509->derCert->buffer; +} + +/* Given an X509_ACERT and EVP_PKEY, verify the acert's signature. + * + * @param [in] x509 the x509 attribute certificate + * @param [in] pkey the evp_pkey + * + * @return WOLFSSL_SUCCESS on verify success + * @return < 0 on error + * */ +int wolfSSL_X509_ACERT_verify(WOLFSSL_X509_ACERT* x509, WOLFSSL_EVP_PKEY* pkey) +{ + int ret = 0; + const byte * der = NULL; + int derSz = 0; + int pkey_type; + + if (x509 == NULL || pkey == NULL) { + WOLFSSL_MSG("error: wolfSSL_X509_ACERT_verify: bad arg"); + return WOLFSSL_FATAL_ERROR; + } + + WOLFSSL_ENTER("wolfSSL_X509_ACERT_verify"); + + der = acert_get_der(x509, &derSz); + + if (der == NULL || derSz <= 0) { + WOLFSSL_MSG("error: wolfSSL_X509_ACERT_verify: get der failed"); + return WOLFSSL_FATAL_ERROR; + } + + switch (pkey->type) { + case EVP_PKEY_RSA: + pkey_type = RSAk; + break; + + case EVP_PKEY_EC: + pkey_type = ECDSAk; + break; + + case EVP_PKEY_DSA: + pkey_type = DSAk; + break; + + default: + WOLFSSL_MSG("error: wolfSSL_X509_ACERT_verify: unknown pkey type"); + return WOLFSSL_FATAL_ERROR; + } + + + ret = VerifyX509Acert(der, (word32)derSz, + (const byte *)pkey->pkey.ptr, pkey->pkey_sz, + pkey_type, x509->heap); + + return ret == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +} + +WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_load_certificate_buffer_ex( + const unsigned char* buf, int sz, int format, void * heap) +{ + int ret = 0; + WOLFSSL_X509_ACERT * x509 = NULL; + DerBuffer * der = NULL; + #ifdef WOLFSSL_SMALL_STACK + DecodedAcert * acert = NULL; + #else + DecodedAcert acert[1]; + #endif + + WOLFSSL_ENTER("wolfSSL_X509_ACERT_load_certificate_buffer"); + + if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + ret = PemToDer(buf, sz, ACERT_TYPE, &der, heap, NULL, NULL); + + if (ret != 0 || der == NULL || der->buffer == NULL) { + WOLFSSL_ERROR(ret); + + if (der != NULL) { + FreeDer(&der); + } + + return NULL; + } + #else + WOLFSSL_ERROR(NOT_COMPILED_IN); + return NULL; + #endif + } + else { + ret = AllocDer(&der, (word32)sz, ACERT_TYPE, heap); + + if (ret != 0 || der == NULL || der->buffer == NULL) { + WOLFSSL_ERROR(ret); + return NULL; + } + + XMEMCPY(der->buffer, buf, sz); + } + + #ifdef WOLFSSL_SMALL_STACK + acert = (DecodedAcert*)XMALLOC(sizeof(DecodedAcert), heap, + DYNAMIC_TYPE_DCERT); + if (acert == NULL) { + WOLFSSL_ERROR(MEMORY_ERROR); + FreeDer(&der); + return NULL; + } + #endif + + InitDecodedAcert(acert, der->buffer, der->length, heap); + + ret = ParseX509Acert(acert, VERIFY_SKIP_DATE); + + if (ret == 0) { + x509 = wolfSSL_X509_ACERT_new_ex(heap); + + if (x509 != NULL) { + ret = CopyDecodedAcertToX509(x509, acert); + + if (ret != 0) { + wolfSSL_X509_ACERT_free(x509); + x509 = NULL; + } + } + else { + ret = MEMORY_ERROR; + } + } + + FreeDecodedAcert(acert); + + #ifdef WOLFSSL_SMALL_STACK + XFREE(acert, heap, DYNAMIC_TYPE_DCERT); + #endif + + FreeDer(&der); + + if (ret != 0) { + WOLFSSL_ERROR(ret); + } + + return x509; +} + +WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_load_certificate_buffer( + const unsigned char* buf, int sz, int format) +{ + return wolfSSL_X509_ACERT_load_certificate_buffer_ex(buf, sz, format, NULL); +} + +/* Retrieve the signature from an ACERT. + * + * @param [in] x509 the x509 attribute certificate + * @param [in, out] buf the signature buffer pointer + * @param [in, out] bufSz the signature buffer size pointer + * + * buf may be null, but bufSz is required. On success, sets + * bufSz pointer to signature length, and copies signature + * to buf if provided. + * + * Returns WWOLFSSL_FATAL_ERROR if bufSz is null or too small. + * Returns WOLFSSL_SUCCESS on success. + */ +int wolfSSL_X509_ACERT_get_signature(WOLFSSL_X509_ACERT* x509, + unsigned char* buf, int* bufSz) +{ + WOLFSSL_ENTER("wolfSSL_X509_ACERT_get_signature"); + + if (x509 == NULL || bufSz == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + /* If buf array is provided, it must be long enough. */ + if (buf != NULL && *bufSz < (int)x509->sig.length) { + return WOLFSSL_FATAL_ERROR; + } + + if (buf != NULL) { + /* Copy in buffer if provided. */ + XMEMCPY(buf, x509->sig.buffer, x509->sig.length); + } + + *bufSz = (int)x509->sig.length; + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_ACERT && (OPENSSL_EXTRA_X509_SMALL || OPENSSL_EXTRA) */ #endif /* !NO_CERTS */ diff --git a/tests/api.c b/tests/api.c index 19b510746..d3310cf53 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14004,6 +14004,152 @@ static int test_wolfSSL_X509_ACERT_misc_api(void) return EXPECT_RESULT(); } +static int test_wolfSSL_X509_ACERT_buffer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_ACERT) && !defined(NO_CERTS) && \ + !defined(NO_RSA) && defined(WC_RSA_PSS) && \ + (defined(OPENSSL_EXTRA_X509_SMALL) || defined(OPENSSL_EXTRA)) + const byte acert_ietf[] = \ + "-----BEGIN ATTRIBUTE CERTIFICATE-----\n" + "MIICPTCCASUCAQEwN6AWMBGkDzANMQswCQYDVQQDDAJDQQIBAqEdpBswGTEXMBUG\n" + "A1UEAwwOc2VydmVyLmV4YW1wbGWgLTArpCkwJzElMCMGA1UEAwwcQXR0cmlidXRl\n" + "IENlcnRpZmljYXRlIElzc3VlcjANBgkqhkiG9w0BAQsFAAIUA7WQWQKiqrVAIUS4\n" + "LE/ZgBtfV8IwIhgPMjAyMTA2MTUxMjM1MDBaGA8yMDMxMDYxMzEyMzUwMFowQTAj\n" + "BggrBgEFBQcKBDEXMBWgCYYHVGVzdHZhbDAIDAZncm91cDEwGgYDVQRIMRMwEaEP\n" + "gw1hZG1pbmlzdHJhdG9yMCwwHwYDVR0jBBgwFoAUYm7JaGdsZLtTgt0tqoCK2MrI\n" + "i10wCQYDVR04BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAlIOJ2Dj3TEUj6BIv6vUs\n" + "GqFWms05i+d10XSzWrunlUTQPoJcUjYkifOWp/7RpZ2XnRl+6hH+nIbmwSmXWwBn\n" + "ERw2bQMmw//nWuN4Qv9t7ltuovWC0pJX6VMT1IRTuTV4SxuZpFL37vkmnFlPBlb+\n" + "mn3ESSxLTjThWFIq1tip4IaxE/i5Uh32GlJglatFHM1PCGoJtyLtYb6KHDlvknw6\n" + "coDyjIcj0FZwtQw41jLwxI8jWNmrpt978wdpprB/URrRs+m02HmeQoiHFi/qvdv8\n" + "d+5vHf3Pi/ulhz/+dvr0p1vEQSoFnYxLXuty2p5m3PJPZCFmT3gURgmgR3BN9d7A\n" + "Bw==\n" + "-----END ATTRIBUTE CERTIFICATE-----\n"; + X509_ACERT * x509 = NULL; + int rc = 0; + byte ietf_serial[] = {0x03, 0xb5, 0x90, 0x59, 0x02, + 0xa2, 0xaa, 0xb5, 0x40, 0x21, + 0x44, 0xb8, 0x2c, 0x4f, 0xd9, + 0x80, 0x1b, 0x5f, 0x57, 0xc2}; + byte serial[64]; + int serial_len = sizeof(serial); + const byte * raw_attr = NULL; + word32 attr_len = 0; + + x509 = wolfSSL_X509_ACERT_load_certificate_buffer_ex(acert_ietf, + sizeof(acert_ietf), + WOLFSSL_FILETYPE_PEM, + HEAP_HINT); + + rc = wolfSSL_X509_ACERT_get_serial_number(x509, serial, &serial_len); + ExpectIntEQ(rc, SSL_SUCCESS); + + ExpectIntEQ(serial_len, 20); + ExpectIntEQ(XMEMCMP(serial, ietf_serial, sizeof(ietf_serial)), 0); + + /* Get the attributes buffer. */ + rc = wolfSSL_X509_ACERT_get_attr_buf(x509, &raw_attr, &attr_len); + ExpectIntEQ(rc, SSL_SUCCESS); + + /* This cert has a 65 byte attributes field. */ + ExpectNotNull(raw_attr); + ExpectIntEQ(attr_len, 65); + + ExpectNotNull(x509); + + if (x509 != NULL) { + wolfSSL_X509_ACERT_free(x509); + x509 = NULL; + } +#endif + return EXPECT_RESULT(); +} + +/* Test ACERT support, but with ASN functions only. + * */ +static int test_wolfSSL_X509_ACERT_asn(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_ACERT) && !defined(NO_CERTS) && \ + !defined(NO_RSA) && defined(WC_RSA_PSS) + const byte acert_ietf[] = \ + "-----BEGIN ATTRIBUTE CERTIFICATE-----\n" + "MIICPTCCASUCAQEwN6AWMBGkDzANMQswCQYDVQQDDAJDQQIBAqEdpBswGTEXMBUG\n" + "A1UEAwwOc2VydmVyLmV4YW1wbGWgLTArpCkwJzElMCMGA1UEAwwcQXR0cmlidXRl\n" + "IENlcnRpZmljYXRlIElzc3VlcjANBgkqhkiG9w0BAQsFAAIUA7WQWQKiqrVAIUS4\n" + "LE/ZgBtfV8IwIhgPMjAyMTA2MTUxMjM1MDBaGA8yMDMxMDYxMzEyMzUwMFowQTAj\n" + "BggrBgEFBQcKBDEXMBWgCYYHVGVzdHZhbDAIDAZncm91cDEwGgYDVQRIMRMwEaEP\n" + "gw1hZG1pbmlzdHJhdG9yMCwwHwYDVR0jBBgwFoAUYm7JaGdsZLtTgt0tqoCK2MrI\n" + "i10wCQYDVR04BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAlIOJ2Dj3TEUj6BIv6vUs\n" + "GqFWms05i+d10XSzWrunlUTQPoJcUjYkifOWp/7RpZ2XnRl+6hH+nIbmwSmXWwBn\n" + "ERw2bQMmw//nWuN4Qv9t7ltuovWC0pJX6VMT1IRTuTV4SxuZpFL37vkmnFlPBlb+\n" + "mn3ESSxLTjThWFIq1tip4IaxE/i5Uh32GlJglatFHM1PCGoJtyLtYb6KHDlvknw6\n" + "coDyjIcj0FZwtQw41jLwxI8jWNmrpt978wdpprB/URrRs+m02HmeQoiHFi/qvdv8\n" + "d+5vHf3Pi/ulhz/+dvr0p1vEQSoFnYxLXuty2p5m3PJPZCFmT3gURgmgR3BN9d7A\n" + "Bw==\n" + "-----END ATTRIBUTE CERTIFICATE-----\n"; + int rc = 0; + byte ietf_serial[] = {0x03, 0xb5, 0x90, 0x59, 0x02, + 0xa2, 0xaa, 0xb5, 0x40, 0x21, + 0x44, 0xb8, 0x2c, 0x4f, 0xd9, + 0x80, 0x1b, 0x5f, 0x57, 0xc2}; + DerBuffer * der = NULL; + #ifdef WOLFSSL_SMALL_STACK + DecodedAcert * acert = NULL; + #else + DecodedAcert acert[1]; + #endif + + rc = wc_PemToDer(acert_ietf, sizeof(acert_ietf), ACERT_TYPE, &der, + HEAP_HINT, NULL, NULL); + + ExpectIntEQ(rc, 0); + ExpectNotNull(der); + + if (der != NULL) { + ExpectNotNull(der->buffer); + } + + #ifdef WOLFSSL_SMALL_STACK + acert = (DecodedAcert*)XMALLOC(sizeof(DecodedAcert), HEAP_HINT, + DYNAMIC_TYPE_DCERT); + ExpectNotNull(acert); + #endif + + #ifdef WOLFSSL_SMALL_STACK + if (acert != NULL) + #endif + { + if (der != NULL && der->buffer != NULL) { + wc_InitDecodedAcert(acert, der->buffer, der->length, HEAP_HINT); + rc = wc_ParseX509Acert(acert, VERIFY_SKIP_DATE); + } + + ExpectIntEQ(acert->serialSz, 20); + ExpectIntEQ(XMEMCMP(acert->serial, ietf_serial, sizeof(ietf_serial)), + 0); + + /* This cert has a 65 byte attributes field. */ + ExpectNotNull(acert->rawAttr); + ExpectIntEQ(acert->rawAttrLen, 65); + } + + #ifdef WOLFSSL_SMALL_STACK + if (acert != NULL) { + XFREE(acert, HEAP_HINT, DYNAMIC_TYPE_DCERT); + acert = NULL; + } + #endif + + if (der != NULL) { + wc_FreeDer(&der); + } + +#endif + return EXPECT_RESULT(); +} + #if !defined(NO_DH) && !defined(NO_AES) && defined(WOLFSSL_CERT_GEN) && \ defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ defined(OPENSSL_EXTRA) && !defined(NO_ASN_TIME) @@ -97322,6 +97468,8 @@ TEST_CASE testCases[] = { /* X509 ACERT tests */ TEST_DECL(test_wolfSSL_X509_ACERT_verify), TEST_DECL(test_wolfSSL_X509_ACERT_misc_api), + TEST_DECL(test_wolfSSL_X509_ACERT_buffer), + TEST_DECL(test_wolfSSL_X509_ACERT_asn), #ifndef NO_BIO TEST_DECL(test_wolfSSL_X509_INFO_multiple_info), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 979326527..11a7226f0 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -41444,6 +41444,31 @@ int VerifyX509Acert(const byte* der, word32 derSz, FREE_ASNGETDATA(dataASN, heap); return ret; } + +void wc_InitDecodedAcert(DecodedAcert* acert, const byte* source, word32 inSz, + void* heap) +{ + InitDecodedAcert(acert, source, inSz, heap); +} + +void wc_FreeDecodedAcert(DecodedAcert * acert) +{ + FreeDecodedAcert(acert); +} + +int wc_ParseX509Acert(DecodedAcert* acert, int verify) +{ + return ParseX509Acert(acert, verify); +} + +int wc_VerifyX509Acert(const byte* acert, word32 acertSz, + const byte* pubKey, word32 pubKeySz, + int pubKeyOID, void * heap) +{ + return VerifyX509Acert(acert, acertSz, pubKey, pubKeySz, + pubKeyOID, heap); +} + #endif /* WOLFSSL_ACERT && WOLFSSL_ASN_TEMPLATE */ #ifdef WOLFSSL_SEP diff --git a/wolfssl/internal.h b/wolfssl/internal.h index af76dcfd1..8469f277e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5367,7 +5367,8 @@ struct WOLFSSL_X509_ACERT { #ifndef NO_CERTS DerBuffer * derCert; #endif - void* heap; + void * heap; + int dynamic; /* whether struct was dynamically allocated */ /* copy of raw Attributes field from */ byte holderSerial[EXTERNAL_SERIAL_SIZE]; int holderSerialSz; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index bf5067d84..3d4f492d8 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3011,9 +3011,12 @@ WOLFSSL_API WOLFSSL_X509_CRL* wolfSSL_X509_CRL_dup(const WOLFSSL_X509_CRL* crl); WOLFSSL_API void wolfSSL_X509_CRL_free(WOLFSSL_X509_CRL *crl); #endif -#if defined(WOLFSSL_ACERT) +#if defined(WOLFSSL_ACERT) && \ + (defined(OPENSSL_EXTRA_X509_SMALL) || defined(OPENSSL_EXTRA)) +WOLFSSL_API WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_new_ex(void * heap); +WOLFSSL_API WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_new(void); WOLFSSL_API void wolfSSL_X509_ACERT_init(WOLFSSL_X509_ACERT * x509, - void* heap); + int dynamic, void * heap); WOLFSSL_API void wolfSSL_X509_ACERT_free(WOLFSSL_X509_ACERT* x509); #ifndef NO_WOLFSSL_STUB WOLFSSL_API int wolfSSL_X509_ACERT_sign(WOLFSSL_X509_ACERT * x509, @@ -3022,8 +3025,14 @@ WOLFSSL_API int wolfSSL_X509_ACERT_sign(WOLFSSL_X509_ACERT * x509, #endif /* !NO_WOLFSSL_STUB */ WOLFSSL_API int wolfSSL_X509_ACERT_verify(WOLFSSL_X509_ACERT* x509, WOLFSSL_EVP_PKEY* pkey); +#if defined(OPENSSL_EXTRA) +WOLFSSL_API int wolfSSL_X509_ACERT_get_signature_nid(const WOLFSSL_X509_ACERT* x); WOLFSSL_API int wolfSSL_X509_ACERT_print(WOLFSSL_BIO* bio, WOLFSSL_X509_ACERT* x509_acert); +WOLFSSL_API WOLFSSL_X509_ACERT * wolfSSL_PEM_read_bio_X509_ACERT( + WOLFSSL_BIO *bp, WOLFSSL_X509_ACERT **x, wc_pem_password_cb *cb, void *u); +WOLFSSL_API long wolfSSL_X509_ACERT_get_version(const WOLFSSL_X509_ACERT *x); +#endif /* OPENSSL_EXTRA */ WOLFSSL_API int wolfSSL_X509_ACERT_get_attr_buf(const WOLFSSL_X509_ACERT* x509, const byte ** rawAttr, word32 * rawAttrLen); @@ -3031,16 +3040,14 @@ WOLFSSL_API int wolfSSL_X509_ACERT_get_serial_number(WOLFSSL_X509_ACERT* x509, unsigned char* in, int * inOutSz); WOLFSSL_API int wolfSSL_X509_ACERT_version(WOLFSSL_X509_ACERT* x509); -WOLFSSL_API long wolfSSL_X509_ACERT_get_version(const WOLFSSL_X509_ACERT *x); -WOLFSSL_API int wolfSSL_X509_ACERT_get_signature_nid(const WOLFSSL_X509_ACERT* x); WOLFSSL_API int wolfSSL_X509_ACERT_get_signature(WOLFSSL_X509_ACERT* x509, unsigned char* buf, int* bufSz); -WOLFSSL_API WOLFSSL_X509_ACERT * wolfSSL_PEM_read_bio_X509_ACERT( - WOLFSSL_BIO *bp, WOLFSSL_X509_ACERT **x, wc_pem_password_cb *cb, void *u); +WOLFSSL_API WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_load_certificate_buffer_ex( + const unsigned char* buf, int sz, int format, void * heap); WOLFSSL_API WOLFSSL_X509_ACERT * wolfSSL_X509_ACERT_load_certificate_buffer( const unsigned char* buf, int sz, int format); -#endif +#endif /* WOLFSSL_ACERT && (OPENSSL_EXTRA_X509_SMALL || OPENSSL_EXTRA) */ WOLFSSL_API const WOLFSSL_ASN1_INTEGER* wolfSSL_X509_REVOKED_get0_serial_number(const diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 0ab2cb73f..ef3f352b3 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2719,7 +2719,6 @@ WOLFSSL_LOCAL void FreeDecodedCRL(DecodedCRL* dcrl); /* Minimal structure for x509 attribute certificate (rfc 5755). * * The attributes field is not parsed, but is stored as raw buffer. - * * */ struct DecodedAcert { word32 certBegin; /* Offset to start of acert. */ diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 50663e8fd..fe15ab09d 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -969,6 +969,19 @@ WOLFSSL_API int wc_GeneratePreTBS(struct DecodedCert* cert, byte *der, int derSz); #endif +#if defined(WOLFSSL_ACERT) +/* Forward declaration needed, as DecodedAcert is defined in asn.h.*/ +struct DecodedAcert; +WOLFSSL_API void wc_InitDecodedAcert(struct DecodedAcert* acert, + const byte* source, word32 inSz, + void* heap); +WOLFSSL_API void wc_FreeDecodedAcert(struct DecodedAcert * acert); +WOLFSSL_API int wc_ParseX509Acert(struct DecodedAcert* acert, int verify); +WOLFSSL_API int wc_VerifyX509Acert(const byte* acert, word32 acertSz, + const byte* pubKey, word32 pubKeySz, + int pubKeyOID, void * heap); +#endif /* WOLFSSL_ACERT */ + #if !defined(XFPRINTF) || defined(NO_FILESYSTEM) || \ defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_ASN_PRINT) #undef WOLFSSL_ASN_PRINT From 410e2f148c1a4fe1427a49019d3de34e2563ee26 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 8 Oct 2024 16:17:16 -0500 Subject: [PATCH 2/5] Missing free call. --- tests/api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/api.c b/tests/api.c index d3310cf53..5ec4bea86 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14133,6 +14133,8 @@ static int test_wolfSSL_X509_ACERT_asn(void) /* This cert has a 65 byte attributes field. */ ExpectNotNull(acert->rawAttr); ExpectIntEQ(acert->rawAttrLen, 65); + + wc_FreeDecodedAcert(acert); } #ifdef WOLFSSL_SMALL_STACK From deda5125983aeced94fb40400c0e0010f132100e Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 8 Oct 2024 17:05:53 -0500 Subject: [PATCH 3/5] acert: fix unused store error. --- tests/api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/api.c b/tests/api.c index 5ec4bea86..5e618619b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14071,8 +14071,7 @@ static int test_wolfSSL_X509_ACERT_buffer(void) static int test_wolfSSL_X509_ACERT_asn(void) { EXPECT_DECLS; -#if defined(WOLFSSL_ACERT) && !defined(NO_CERTS) && \ - !defined(NO_RSA) && defined(WC_RSA_PSS) +#if defined(WOLFSSL_ACERT) && !defined(NO_CERTS) const byte acert_ietf[] = \ "-----BEGIN ATTRIBUTE CERTIFICATE-----\n" "MIICPTCCASUCAQEwN6AWMBGkDzANMQswCQYDVQQDDAJDQQIBAqEdpBswGTEXMBUG\n" @@ -14124,6 +14123,7 @@ static int test_wolfSSL_X509_ACERT_asn(void) if (der != NULL && der->buffer != NULL) { wc_InitDecodedAcert(acert, der->buffer, der->length, HEAP_HINT); rc = wc_ParseX509Acert(acert, VERIFY_SKIP_DATE); + ExpectIntEQ(rc, 0); } ExpectIntEQ(acert->serialSz, 20); From bed680a96c8cb4a5aa7022b7a1fe43aa1c4af76d Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 8 Oct 2024 20:47:49 -0500 Subject: [PATCH 4/5] acert: line length. --- wolfssl/ssl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 3d4f492d8..288bccb8d 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3026,7 +3026,8 @@ WOLFSSL_API int wolfSSL_X509_ACERT_sign(WOLFSSL_X509_ACERT * x509, WOLFSSL_API int wolfSSL_X509_ACERT_verify(WOLFSSL_X509_ACERT* x509, WOLFSSL_EVP_PKEY* pkey); #if defined(OPENSSL_EXTRA) -WOLFSSL_API int wolfSSL_X509_ACERT_get_signature_nid(const WOLFSSL_X509_ACERT* x); +WOLFSSL_API int wolfSSL_X509_ACERT_get_signature_nid( + const WOLFSSL_X509_ACERT* x); WOLFSSL_API int wolfSSL_X509_ACERT_print(WOLFSSL_BIO* bio, WOLFSSL_X509_ACERT* x509_acert); WOLFSSL_API WOLFSSL_X509_ACERT * wolfSSL_PEM_read_bio_X509_ACERT( From 244fff844fe4f3562bb896ff2914304210c6074c Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 8 Oct 2024 21:21:25 -0500 Subject: [PATCH 5/5] acert: pacify c++ style comment warning. --- tests/api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/api.c b/tests/api.c index 5e618619b..d9c7df0ab 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14020,7 +14020,7 @@ static int test_wolfSSL_X509_ACERT_buffer(void) "gw1hZG1pbmlzdHJhdG9yMCwwHwYDVR0jBBgwFoAUYm7JaGdsZLtTgt0tqoCK2MrI\n" "i10wCQYDVR04BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAlIOJ2Dj3TEUj6BIv6vUs\n" "GqFWms05i+d10XSzWrunlUTQPoJcUjYkifOWp/7RpZ2XnRl+6hH+nIbmwSmXWwBn\n" - "ERw2bQMmw//nWuN4Qv9t7ltuovWC0pJX6VMT1IRTuTV4SxuZpFL37vkmnFlPBlb+\n" + "ERw2bQMmw/""/nWuN4Qv9t7ltuovWC0pJX6VMT1IRTuTV4SxuZpFL37vkmnFlPBlb+\n" "mn3ESSxLTjThWFIq1tip4IaxE/i5Uh32GlJglatFHM1PCGoJtyLtYb6KHDlvknw6\n" "coDyjIcj0FZwtQw41jLwxI8jWNmrpt978wdpprB/URrRs+m02HmeQoiHFi/qvdv8\n" "d+5vHf3Pi/ulhz/+dvr0p1vEQSoFnYxLXuty2p5m3PJPZCFmT3gURgmgR3BN9d7A\n" @@ -14082,7 +14082,7 @@ static int test_wolfSSL_X509_ACERT_asn(void) "gw1hZG1pbmlzdHJhdG9yMCwwHwYDVR0jBBgwFoAUYm7JaGdsZLtTgt0tqoCK2MrI\n" "i10wCQYDVR04BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAlIOJ2Dj3TEUj6BIv6vUs\n" "GqFWms05i+d10XSzWrunlUTQPoJcUjYkifOWp/7RpZ2XnRl+6hH+nIbmwSmXWwBn\n" - "ERw2bQMmw//nWuN4Qv9t7ltuovWC0pJX6VMT1IRTuTV4SxuZpFL37vkmnFlPBlb+\n" + "ERw2bQMmw/""/nWuN4Qv9t7ltuovWC0pJX6VMT1IRTuTV4SxuZpFL37vkmnFlPBlb+\n" "mn3ESSxLTjThWFIq1tip4IaxE/i5Uh32GlJglatFHM1PCGoJtyLtYb6KHDlvknw6\n" "coDyjIcj0FZwtQw41jLwxI8jWNmrpt978wdpprB/URrRs+m02HmeQoiHFi/qvdv8\n" "d+5vHf3Pi/ulhz/+dvr0p1vEQSoFnYxLXuty2p5m3PJPZCFmT3gURgmgR3BN9d7A\n"