├── .gitignore ├── .vimrc ├── COPYING ├── Makefile ├── README.md ├── TrustStore.pem ├── agent1-cert.pem ├── asn1.c ├── basic.c ├── bignum.c ├── bio.c ├── bio_in_mem.c ├── bio_in_mem_nodejs.c ├── bio_read_file.c ├── bio_ssl.c ├── cprovider.c ├── decoder.c ├── dh.c ├── dh_1_1_1.c ├── digest.c ├── distribution.cc ├── dsa.c ├── dsa_private_encrypted_1025.pem ├── ec-keygen.c ├── ec.c ├── engine.c ├── err.c ├── evp-pkey.c ├── fips-provider.c ├── fips.cnf ├── generator.cc ├── hash.c ├── hmac.c ├── is_fips_enabled.c ├── keymgmt.c ├── notes ├── aes.md ├── asn1.md ├── bignum.md ├── building.md ├── certs.md ├── des.md ├── dh.md ├── digital-signatures.md ├── ec.png ├── elgamal.md ├── elliptic-curve.md ├── err.md ├── fips-enabled-failure.md ├── fips.md ├── hash.md ├── hmac.md ├── issues │ ├── crypto-dh-stateless-issue.md │ ├── fips-ci-issues.md │ ├── fips-ubi8-issue.md │ ├── issues.md │ ├── node-openssl-build.md │ ├── node-openssl-cli.md │ ├── openssl_init_crypto_issue.md │ ├── p2align-aix-issue.md │ ├── quictls-openssl.md │ ├── rand-node-mksnapshot-issue.md │ ├── refcount-issue.md │ ├── tls-min-max-version-issue.md │ ├── tls-renegotiation-issue.md │ ├── win-v2019-arm64.md │ └── wrong-tag-issue2.md ├── modes.md ├── node_openssl_config.md ├── padding.md ├── providers.md ├── rsa.md ├── testing.md ├── tls.md ├── tls1.3.md └── webcrypto.md ├── openssl.cnf ├── pem_key_read.c ├── private.c ├── provider.c ├── rand.c ├── rand_status.c ├── random_bytes.c ├── rsa.c ├── rsa_cert.crt ├── rsa_data_too_large.c ├── rsa_private.pem ├── rsa_pss.c ├── rsa_sign.c ├── s_client.sh ├── s_server.sh ├── secp256k1-key.pem ├── sign.c ├── socket.c ├── src ├── array-overflow.c └── certificate │ ├── cert-body.bin │ ├── cert.pem │ ├── issuer-pub.pem │ ├── signature-decrypted.bin │ ├── signature.bin │ └── signature.txt ├── ssl.c ├── store.c ├── test.crt ├── test.key ├── wrong-tag.c ├── wrong-tag2.c └── x509.c /.gitignore: -------------------------------------------------------------------------------- 1 | array-overflow 2 | asn1 3 | basic 4 | bignum 5 | bio 6 | bio_in_mem 7 | bio_in_mem_nodejs 8 | bio_read_file 9 | bio_ssl 10 | decoder 11 | derive 12 | dh 13 | dh_1_1_1 14 | digest 15 | distribution 16 | dsa 17 | ec 18 | ec-keygen 19 | engine 20 | err 21 | evp-pkey 22 | fips-provider 23 | generator 24 | hash 25 | hmac 26 | is_fips_enabled 27 | keymgmt 28 | md 29 | pem_key_read 30 | private 31 | provider 32 | rand 33 | rand_status 34 | random 35 | random_bytes 36 | rsa 37 | rsa_data_too_large 38 | rsa_pss 39 | rsa_sign 40 | socket 41 | ssl 42 | sign 43 | store 44 | wrong-tag 45 | wrong-tag2 46 | x509 47 | config.mk 48 | *.core 49 | *.dSYM 50 | *.i 51 | *.o 52 | *.so 53 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | let &path.="../openssl/" 2 | 3 | let g:syntastic_mode_map = { 'mode': 'passive', 'active_filetypes': [],'passive_filetypes': [] } 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2017-2023 Daniel Bevenius 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 21 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | sinclude config.mk 2 | 3 | OPENSSL_PREFIX?= /usr 4 | 5 | OPENSSL_SRC?= 6 | 7 | OPENSSL_INC?= $(OPENSSL_PREFIX)/include 8 | OPENSSL_LIB?= $(OPENSSL_PREFIX)/lib 9 | 10 | # Mute clang color-based warnings. 11 | #CFLAGS+= -fno-color-diagnostics 12 | CFLAGS+= -Wall -g -O0 -I$(OPENSSL_INC) 13 | CFLAGS+= -std=c99 14 | 15 | LDLIBS+= -lcrypto -lssl 16 | 17 | LDFLAGS= -L$(OPENSSL_LIB) -L$(OPENSSL_LIB)/ossl-modules 18 | LDFLAGS+= -Wl,-rpath,$(OPENSSL_LIB) -Wl,-rpath,$(OPENSSL_LIB)/ossl-modules 19 | 20 | RM?= rm -f 21 | 22 | CPP_FILES+= asn1.i 23 | CPP_FILES+= err.i 24 | 25 | PROGS+= array-overflow 26 | PROGS+= asn1 27 | PROGS+= basic 28 | PROGS+= bignum 29 | PROGS+= bio 30 | PROGS+= bio_in_mem 31 | PROGS+= bio_in_mem_nodejs 32 | PROGS+= bio_read_file 33 | PROGS+= bio_ssl 34 | PROGS+= decoder 35 | # XXX: dh segfaults with 3.0.9. 36 | #PROGS+= dh 37 | PROGS+= dh_1_1_1 38 | PROGS+= distribution 39 | PROGS+= digest 40 | PROGS+= dsa 41 | PROGS+= ec 42 | PROGS+= ec-keygen 43 | PROGS+= err 44 | ifneq ($(OPENSSL_SRC),) 45 | # XXX: requires internal headers; doesn't compile with prebuilt binary packages. 46 | PROGS+= evp-pkey 47 | endif 48 | # XXX: does not compile/link (bad symbols). 49 | PROGS+= fips-provider 50 | PROGS+= generator 51 | PROGS+= hash 52 | PROGS+= hmac 53 | PROGS+= is_fips_enabled 54 | PROGS+= keymgmt 55 | PROGS+= pem_key_read 56 | PROGS+= private 57 | PROGS+= provider 58 | PROGS+= rand 59 | PROGS+= rand_status 60 | PROGS+= rsa 61 | PROGS+= rsa_data_too_large 62 | PROGS+= rsa_pss 63 | PROGS+= rsa_sign 64 | PROGS+= store 65 | PROGS+= x509 66 | PROGS+= random_bytes 67 | PROGS+= socket 68 | PROGS+= sign 69 | PROGS+= ssl 70 | PROGS+= wrong-tag 71 | PROGS+= wrong-tag2 72 | 73 | LIBS+= libcprovider.so 74 | LIBS+= libengine.so 75 | 76 | asn1.i: asn1.c 77 | 78 | WNO_ERROR_DEPRECATED= -Wno-error=deprecated 79 | 80 | array-overflow.o: src/array-overflow.c 81 | $(COMPILE.c) $< 82 | 83 | dh: CFLAGS+= $(WNO_ERROR_DEPRECATED) 84 | ec: CFLAGS+= $(WNO_ERROR_DEPRECATED) 85 | ec-keygen: LDLIBS+= -lpthread 86 | 87 | engine.o: CFLAGS+= -fPIC 88 | libengine.so: engine.o 89 | $(CC) -shared -fPIC $(CFLAGS) $(LDFLAGS) -o $@ $^ 90 | 91 | err.i: err.c 92 | 93 | %.i: %.c 94 | $(CC) -E $(CFLAGS) $(OUTPUT_OPTION) $< 95 | 96 | %.i: %.cc 97 | $(CXX) -E $(CXXFLAGS) $(OUTPUT_OPTION) $< 98 | 99 | evp-pkey: CFLAGS+= $(WNO_ERROR_DEPRECATED) 100 | 101 | keymgmt: LDLIBS+= -lpthread 102 | 103 | cprovider.o: CFLAGS+= -fPIC -I. 104 | libcprovider.so: cprovider.o 105 | $(CC) -shared -fPIC $(CFLAGS) $(LDFLAGS) -o $@ $^ 106 | 107 | .DEFAULT: all 108 | all: $(CPP_FILES) $(LIBS) $(PROGS) 109 | 110 | .PHONY: run 111 | run: $(PROGS) 112 | for prog in $(PROGS); do \ 113 | printf "%s ...\n" "$$prog"; \ 114 | ./$$prog; \ 115 | done; \ 116 | ./test_engine.sh 117 | 118 | .PHONY: clean 119 | clean: 120 | $(RM) $(CPP_FILES) 121 | $(RM) $(LIBS) 122 | $(RM) $(PROGS) 123 | $(RM) *.o 124 | -------------------------------------------------------------------------------- /agent1-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC2DCCAkGgAwIBAgIJAOzJuFYnDamoMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV 3 | BAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoMBkpveWVu 4 | dDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAwHgYJKoZIhvcNAQkB 5 | FhFyeUB0aW55Y2xvdWRzLm9yZzAgFw0xODExMTYxODQyMjFaGA8yMjkyMDgzMDE4 6 | NDIyMVowfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEP 7 | MA0GA1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQ8wDQYDVQQDDAZhZ2Vu 8 | dDExIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMIGfMA0GCSqGSIb3 9 | DQEBAQUAA4GNADCBiQKBgQDvVEBwFjfiirsDjlZB+CjYNMNCqdJe27hqK/b72AnL 10 | jgN6mLcXCOABJC5N61TGFkiF9Zndh6IyFXRZVb4gQX4zxNDRuAydo95BmiYHGV0v 11 | t1ZXsLv7XrfQu6USLRtpZMe1cNULjsAB7raN+1hEN1CPMSmSjWc7MKPgv09QYJ5j 12 | cQIDAQABo2EwXzBdBggrBgEFBQcBAQRRME8wIwYIKwYBBQUHMAGGF2h0dHA6Ly9v 13 | Y3NwLm5vZGVqcy5vcmcvMCgGCCsGAQUFBzAChhxodHRwOi8vY2Eubm9kZWpzLm9y 14 | Zy9jYS5jZXJ0MA0GCSqGSIb3DQEBCwUAA4GBAHrKvx2Z4fsF7b3VRgiIbdbFCfxY 15 | ICvoJ0+BObYPjqIZZm9+/5c36SpzKzGO9CN9qUEj3KxPmijnb+Zjsm1CSCrG1m04 16 | C73+AjAIPnQ+eWZnF1K4L2kuEDTpv8nQzYKYiGxsmW58PSMeAq1TmaFwtSW3TxHX 17 | 7ROnqBX0uXQlOo1m 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /asn1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * something_st ::= SEQUENCE { 9 | * age INTEGER 10 | * } 11 | */ 12 | struct something_st { 13 | ASN1_OCTET_STRING* name; 14 | int32_t age; 15 | }; 16 | 17 | typedef struct something_st something; 18 | 19 | static int something_cb(int operation, 20 | ASN1_VALUE **pval, 21 | const ASN1_ITEM *it, 22 | void *exarg) { 23 | printf("something_cb: operation=%d\n", operation); 24 | return 1; 25 | } 26 | 27 | ASN1_SEQUENCE_cb(something, something_cb) = { 28 | ASN1_SIMPLE(something, name, ASN1_OCTET_STRING), 29 | ASN1_EMBED(something, age, INT32) 30 | } ASN1_SEQUENCE_END_cb(something, something) 31 | 32 | IMPLEMENT_ASN1_FUNCTIONS(something) 33 | 34 | int main(int argc, char** argv) { 35 | printf("OpenSSL asn1 example\n"); 36 | 37 | const char* name = "Fletch"; 38 | ASN1_OCTET_STRING* asn1_name = ASN1_OCTET_STRING_new(); 39 | ASN1_OCTET_STRING_set(asn1_name, (const unsigned char*)name, strlen(name)); 40 | 41 | something s = { .name = asn1_name, .age = 46 }; 42 | unsigned char* out = NULL; 43 | // internal C structure to DER binary format 44 | int len = i2d_something(&s, &out); 45 | if (len) { 46 | printf("Encoded something {%d} into: %s\n", s.age, out); 47 | } 48 | 49 | const unsigned char* encoded_something = out; 50 | // DER binary format to internal C structure 51 | something* decoded = d2i_something(NULL, &encoded_something, len); 52 | printf("Decoded something: name: %s, age: %d\n", decoded->name->data, decoded->age); 53 | 54 | int length = decoded->name->length; 55 | int type = decoded->name->type; 56 | const unsigned char* data = ASN1_STRING_get0_data(decoded->name); 57 | long flags = decoded->name->flags; 58 | 59 | ERR_print_errors_fp(stdout); 60 | something_free(decoded); 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /basic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int encrypt(unsigned char *plaintext, 8 | int plaintext_len, 9 | unsigned char *key, 10 | unsigned char *iv, 11 | unsigned char *ciphertext); 12 | 13 | int decrypt(unsigned char *ciphertext, 14 | int ciphertext_len, 15 | unsigned char *key, 16 | unsigned char *iv, 17 | unsigned char *plaintext); 18 | 19 | void handleErrors(void); 20 | 21 | int main(int arc, char *argv[]) { 22 | /* Load the human readable error strings for libcrypto */ 23 | ERR_load_crypto_strings(); 24 | 25 | /* Load all digest and cipher algorithms */ 26 | OpenSSL_add_all_algorithms(); 27 | 28 | /* Load config file, and other important initialisation */ 29 | //OPENSSL_config(NULL); 30 | OPENSSL_no_config(); 31 | 32 | unsigned char *key = (unsigned char *)"01234567890123456789012345678901"; 33 | unsigned char *iv = (unsigned char *)"someIV"; 34 | unsigned char *plaintext = (unsigned char *) "Bajja"; 35 | unsigned char ciphertext[128]; 36 | unsigned char decryptedtext[128]; 37 | 38 | int decryptedtext_len, ciphertext_len; 39 | ciphertext_len = encrypt(plaintext, strlen ((char *)plaintext), key, iv, ciphertext); 40 | printf("Ciphertext is:\n"); 41 | BIO_dump_fp(stdout, (const char *)ciphertext, ciphertext_len); 42 | 43 | decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv, decryptedtext); 44 | decryptedtext[decryptedtext_len] = '\0'; 45 | printf("Decrypted text is:\n"); 46 | printf("%s\n", decryptedtext); 47 | 48 | /* Removes all digests and ciphers */ 49 | EVP_cleanup(); 50 | 51 | /* if you omit the next, a small leak may be left when you make use of the BIO (low level API) for e.g. base64 transformations */ 52 | CRYPTO_cleanup_all_ex_data(); 53 | 54 | /* Remove error strings */ 55 | ERR_free_strings(); 56 | 57 | return 0; 58 | } 59 | 60 | int encrypt(unsigned char* plaintext, 61 | int plaintext_len, 62 | unsigned char* key, 63 | unsigned char* iv, 64 | unsigned char* ciphertext) { 65 | EVP_CIPHER_CTX* ctx; 66 | int len; 67 | int ciphertext_len; 68 | 69 | /* Create and initialise the context */ 70 | if(!(ctx = EVP_CIPHER_CTX_new())) { 71 | handleErrors(); 72 | } 73 | 74 | /* Initialise the encryption operation. IMPORTANT - ensure you use a key 75 | * and IV size appropriate for your cipher 76 | * In this example we are using 256 bit AES (i.e. a 256 bit key). The 77 | * IV size for *most* modes is the same as the block size. For AES this 78 | * is 128 bits */ 79 | if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { 80 | handleErrors(); 81 | } 82 | 83 | /* Provide the message to be encrypted, and obtain the encrypted output. 84 | * EVP_EncryptUpdate can be called multiple times if necessary 85 | */ 86 | if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) { 87 | handleErrors(); 88 | } 89 | ciphertext_len = len; 90 | 91 | /* Finalise the encryption. Further ciphertext bytes may be written at 92 | * this stage. 93 | */ 94 | if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) { 95 | handleErrors(); 96 | } 97 | ciphertext_len += len; 98 | 99 | /* Clean up */ 100 | EVP_CIPHER_CTX_free(ctx); 101 | return ciphertext_len; 102 | } 103 | 104 | int decrypt(unsigned char* ciphertext, 105 | int ciphertext_len, 106 | unsigned char* key, 107 | unsigned char* iv, 108 | unsigned char* plaintext) { 109 | EVP_CIPHER_CTX* ctx; 110 | int len; 111 | int plaintext_len; 112 | 113 | /* Create and initialise the context */ 114 | if(!(ctx = EVP_CIPHER_CTX_new())) { 115 | handleErrors(); 116 | } 117 | 118 | /* Initialise the decryption operation. IMPORTANT - ensure you use a key 119 | * and IV size appropriate for your cipher 120 | * In this example we are using 256 bit AES (i.e. a 256 bit key). The 121 | * IV size for *most* modes is the same as the block size. For AES this 122 | * is 128 bits */ 123 | if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { 124 | handleErrors(); 125 | } 126 | 127 | /* Provide the message to be decrypted, and obtain the plaintext output. 128 | * EVP_DecryptUpdate can be called multiple times if necessary 129 | */ 130 | if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) { 131 | handleErrors(); 132 | } 133 | plaintext_len = len; 134 | 135 | /* Finalise the decryption. Further plaintext bytes may be written at 136 | * this stage. 137 | */ 138 | if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { 139 | handleErrors(); 140 | } 141 | plaintext_len += len; 142 | 143 | /* Clean up */ 144 | EVP_CIPHER_CTX_free(ctx); 145 | return plaintext_len; 146 | } 147 | 148 | void handleErrors(void) { 149 | ERR_print_errors_fp(stderr); 150 | abort(); 151 | } 152 | 153 | -------------------------------------------------------------------------------- /bignum.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char** argv) { 7 | printf("BIGNUM example\n"); 8 | BIGNUM* nr = BN_new(); 9 | BN_set_word(nr, 3); 10 | printf("nr: %lu\n", BN_get_word(nr)); 11 | 12 | BIGNUM* nr2 = BN_new(); 13 | BN_set_word(nr2, 1); 14 | printf("nr comp nr2: %d\n", BN_cmp(nr, nr2)); 15 | printf("nr2 comp nr: %d\n", BN_cmp(nr2, nr)); 16 | BN_free(nr); 17 | 18 | exit(EXIT_SUCCESS); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /bio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | long bio_callback(BIO *b, 8 | int oper, 9 | const char *argp, 10 | size_t len, 11 | int argi, 12 | long argl, 13 | int ret, 14 | size_t *processed) { 15 | printf("bio_callback[bio_method_name=%s, operation=%d]\n", BIO_method_name(b), oper); 16 | return ret; 17 | } 18 | 19 | int main(int arc, char *argv[]) { 20 | 21 | ERR_load_crypto_strings(); 22 | OpenSSL_add_all_algorithms(); 23 | OPENSSL_no_config(); 24 | 25 | printf("Creating BIO to stdout...\n"); 26 | 27 | BIO* bout = BIO_new_fp(stdout, BIO_NOCLOSE); 28 | BIO_set_callback_ex(bout, bio_callback); 29 | BIO_set_init(bout, 1); 30 | int r = BIO_write(bout, "bajja\n", 6); 31 | printf("wrote %d\n", r); 32 | 33 | BIO_ctrl(bout, BIO_CTRL_RESET, 0, NULL); 34 | 35 | EVP_cleanup(); 36 | CRYPTO_cleanup_all_ex_data(); 37 | ERR_free_strings(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /bio_in_mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct buffer { 7 | unsigned char* data; 8 | size_t len; 9 | size_t read_position; 10 | }; 11 | 12 | int read(BIO* bio, char* c, int len) { 13 | printf("%s read\n", BIO_method_name(bio)); 14 | 15 | // Get buffer from bio. 16 | struct buffer* buf = BIO_get_data(bio); 17 | if (buf->read_position == buf->len) 18 | return 0; 19 | 20 | size_t space_left = buf->len - buf->read_position; 21 | size_t to_read = len < space_left ? len : space_left; 22 | 23 | printf("to_read: %zu\n", to_read); 24 | memcpy(c, buf->data, to_read); 25 | buf->read_position += to_read; 26 | buf->len -= to_read; 27 | return to_read; 28 | } 29 | 30 | long ctrl(BIO* bio, int cmd, long larg, void* parg) { 31 | struct buffer* buf = BIO_get_data(bio); 32 | 33 | switch (cmd) { 34 | case BIO_C_FILE_TELL: 35 | printf("cmd was BIO_C_FILE_TELL\n"); 36 | return 0; 37 | case BIO_CTRL_EOF: 38 | printf("cmd was BIO_CTRL_EOF, buf->len: %zu\n", buf->len); 39 | return buf->len == 0; 40 | }; 41 | 42 | return 0; 43 | } 44 | 45 | int main(int arc, char *argv[]) { 46 | printf("BIO in memory example\n"); 47 | BIO_METHOD* method; 48 | BIO* file_bio; 49 | BIO* in_mem_bio; 50 | 51 | file_bio = BIO_new_file("./rsa_private.pem", "r"); 52 | unsigned char data[4096]; 53 | int length = BIO_read(file_bio, data, sizeof(data)); 54 | 55 | method = BIO_meth_new(BIO_TYPE_MEM, "In-Memory BIO"); 56 | BIO_meth_set_read(method, read); 57 | BIO_meth_set_ctrl(method, ctrl); 58 | in_mem_bio = BIO_new(method); 59 | struct buffer buf = { 60 | .data = data, 61 | .len = length, 62 | .read_position = 0 63 | }; 64 | // Attach our buffer struct to the BIO. 65 | BIO_set_data(in_mem_bio, (void*)&buf); 66 | 67 | int ret; 68 | 69 | ret = BIO_eof(in_mem_bio); 70 | printf("BIO_eof: %d\n", ret); 71 | 72 | unsigned char b[length]; 73 | ret = BIO_read(in_mem_bio, b, length); 74 | printf("Read: %d\n", ret); 75 | 76 | ret = BIO_tell(in_mem_bio); 77 | printf("BIO_tell: %d\n", ret); 78 | 79 | ret = BIO_eof(in_mem_bio); 80 | printf("BIO_eof: %d\n", ret); 81 | 82 | BIO_free(file_bio); 83 | BIO_free(in_mem_bio); 84 | exit(EXIT_SUCCESS); 85 | } 86 | -------------------------------------------------------------------------------- /bio_in_mem_nodejs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct buffer { 10 | size_t len; 11 | size_t read_pos; 12 | size_t write_pos; 13 | struct buffer *next; 14 | char *data; 15 | }; 16 | typedef struct buffer buffer; 17 | 18 | struct node_bio { 19 | size_t initial; 20 | size_t length; 21 | size_t allocate_hint; 22 | int eof_return; 23 | struct buffer *read_head; 24 | struct buffer *write_head; 25 | }; 26 | typedef struct node_bio node_bio; 27 | 28 | void try_move_read_head(node_bio *nbio); 29 | void free_empty(node_bio *nbio); 30 | 31 | size_t node_bio_read(node_bio *nbio, char *out, size_t size) { 32 | size_t bytes_read; 33 | size_t expected; 34 | size_t offset; 35 | size_t left; 36 | 37 | bytes_read = 0; 38 | expected = nbio->length > size ? size : nbio->length; 39 | offset = 0; 40 | left = size; 41 | 42 | while (bytes_read < expected) { 43 | size_t avail = nbio->read_head->write_pos - nbio->read_head->read_pos; 44 | if (avail > left) 45 | avail = left; 46 | 47 | if (out != NULL) 48 | memcpy(out + offset, 49 | nbio->read_head->data + nbio->read_head->read_pos, 50 | avail); 51 | nbio->read_head->read_pos += avail; 52 | 53 | // Move pointers 54 | bytes_read += avail; 55 | offset += avail; 56 | left -= avail; 57 | 58 | try_move_read_head(nbio); 59 | } 60 | nbio->length -= bytes_read; 61 | 62 | // Free all empty buffers, but write_head's child 63 | free_empty(nbio); 64 | 65 | return bytes_read; 66 | } 67 | 68 | void free_empty(node_bio *nbio) { 69 | if (nbio->write_head == NULL) 70 | return; 71 | buffer *child = nbio->write_head->next; 72 | if (child == nbio->write_head || child == nbio->read_head) 73 | return; 74 | buffer *cur = child->next; 75 | if (cur == nbio->write_head || cur == nbio->read_head) 76 | return; 77 | 78 | buffer *prev = child; 79 | while (cur != nbio->read_head) { 80 | buffer *next = cur->next; 81 | free(cur->data); 82 | cur = next; 83 | } 84 | prev->next = cur; 85 | } 86 | 87 | void try_move_read_head(node_bio *nbio) { 88 | // `read_pos_` and `write_pos_` means the position of the reader and writer 89 | // inside the buffer, respectively. When they're equal - its safe to reset 90 | // them, because both reader and writer will continue doing their stuff 91 | // from new (zero) positions. 92 | while (nbio->read_head->read_pos != 0 && 93 | nbio->read_head->read_pos == nbio->read_head->write_pos) { 94 | // Reset positions 95 | nbio->read_head->read_pos = 0; 96 | nbio->read_head->write_pos = 0; 97 | 98 | // Move read_head_ forward, just in case if there're still some data to 99 | // read in the next buffer. 100 | if (nbio->read_head != nbio->write_head) 101 | nbio->read_head = nbio->read_head->next; 102 | } 103 | } 104 | 105 | 106 | int read(BIO *bio, char *out, int len) { 107 | printf("%s read\n", BIO_method_name(bio)); 108 | 109 | // Get buffer from bio. 110 | node_bio *nbio = BIO_get_data(bio); 111 | int bytes = node_bio_read(nbio, out, len); 112 | if (bytes == 0) { 113 | bytes = nbio->eof_return; 114 | if (bytes != 0) { 115 | BIO_set_retry_read(bio); 116 | } 117 | } 118 | return bytes; 119 | } 120 | 121 | void try_allocate_for_write(node_bio *nbio, size_t hint) { 122 | buffer *w; 123 | buffer *r; 124 | w = nbio->write_head; 125 | r = nbio->read_head; 126 | // If write head is full, next buffer is either read head or not empty. 127 | if (w == NULL || 128 | (w->write_pos == w->len && 129 | (w->next == r || w->next->write_pos != 0))) { 130 | size_t len = w == NULL ? nbio->initial : 16384; 131 | if (len < hint) 132 | len = hint; 133 | 134 | // If there is a one time allocation size hint, use it. 135 | if (nbio->allocate_hint > len) { 136 | len = nbio->allocate_hint; 137 | nbio->allocate_hint = 0; 138 | } 139 | 140 | //buffer* next = new Buffer(env_, len); 141 | buffer *next = (buffer*) malloc(sizeof(buffer)); 142 | next->len = len; 143 | next->read_pos = 0; 144 | next->write_pos = 0; 145 | next->next = NULL; 146 | next->data = (char*) malloc(sizeof(char) * len); 147 | 148 | if (w == NULL) { 149 | next->next = next; 150 | nbio->write_head = next; 151 | nbio->read_head = next; 152 | } else { 153 | next->next = w->next; 154 | w->next = next; 155 | } 156 | } 157 | } 158 | 159 | void node_bio_write(node_bio *nbio, const char *data, size_t size) { 160 | size_t offset; 161 | size_t left; 162 | offset = 0; 163 | left = size; 164 | 165 | // Allocate initial buffer if the ring is empty 166 | try_allocate_for_write(nbio, left); 167 | 168 | while (left > 0) { 169 | size_t to_write = left; 170 | //CHECK_LE(write_head_->write_pos_, write_head_->len_); 171 | size_t avail = nbio->write_head->len - nbio->write_head->write_pos; 172 | 173 | if (to_write > avail) 174 | to_write = avail; 175 | 176 | // Copy data 177 | memcpy(nbio->write_head->data + nbio->write_head->write_pos, 178 | data + offset, 179 | to_write); 180 | 181 | // Move pointers 182 | left -= to_write; 183 | offset += to_write; 184 | nbio->length += to_write; 185 | nbio->write_head->write_pos += to_write; 186 | //CHECK_LE(write_head_->write_pos_, write_head_->len_); 187 | 188 | // Go to next buffer if there still are some bytes to write 189 | if (left != 0) { 190 | //CHECK_EQ(write_head_->write_pos_, write_head_->len_); 191 | try_allocate_for_write(nbio, left); 192 | nbio->write_head = nbio->write_head->next; 193 | 194 | // Additionally, since we're moved to the next buffer, read head 195 | // may be moved as well. 196 | try_move_read_head(nbio); 197 | } 198 | } 199 | //CHECK_EQ(left, 0); 200 | } 201 | 202 | int write(BIO *bio, const char *data, int len) { 203 | BIO_clear_retry_flags(bio); 204 | 205 | node_bio *nbio = BIO_get_data(bio); 206 | node_bio_write(nbio, data, len); 207 | 208 | return len; 209 | } 210 | 211 | 212 | void reset(node_bio *nbio) { 213 | if (nbio->read_head == NULL) 214 | return; 215 | 216 | while (nbio->read_head->read_pos != nbio->read_head->write_pos) { 217 | nbio->length -= nbio->read_head->write_pos - nbio->read_head->read_pos; 218 | nbio->read_head->write_pos = 0; 219 | nbio->read_head->read_pos = 0; 220 | 221 | nbio->read_head = nbio->read_head->next; 222 | } 223 | nbio->write_head = nbio->read_head; 224 | } 225 | 226 | long ctrl(BIO *bio, int cmd, long larg, void *parg) { 227 | node_bio *nbio; 228 | long ret; 229 | nbio = BIO_get_data(bio); 230 | ret = 1; 231 | 232 | switch (cmd) { 233 | case BIO_CTRL_RESET: 234 | reset(nbio); 235 | break; 236 | case BIO_CTRL_EOF: 237 | ret = nbio->length == 0; 238 | break; 239 | case BIO_C_SET_BUF_MEM_EOF_RETURN: 240 | nbio->eof_return = larg; 241 | break; 242 | case BIO_CTRL_INFO: 243 | ret = nbio->length; 244 | if (parg != NULL) 245 | *((void**)parg) = NULL; 246 | break; 247 | case BIO_C_SET_BUF_MEM: 248 | assert(0); // "Can't use SET_BUF_MEM_PTR with NodeBIO" 249 | break; 250 | case BIO_C_GET_BUF_MEM_PTR: 251 | assert(0); // "Can't use GET_BUF_MEM_PTR with NodeBIO" 252 | ret = 0; 253 | break; 254 | case BIO_CTRL_GET_CLOSE: 255 | ret = BIO_get_shutdown(bio); 256 | break; 257 | case BIO_CTRL_SET_CLOSE: 258 | BIO_set_shutdown(bio, larg); 259 | break; 260 | case BIO_CTRL_WPENDING: 261 | ret = 0; 262 | break; 263 | case BIO_CTRL_PENDING: 264 | ret = nbio->length; 265 | break; 266 | case BIO_CTRL_DUP: 267 | case BIO_CTRL_FLUSH: 268 | ret = 1; 269 | break; 270 | case BIO_CTRL_PUSH: 271 | case BIO_CTRL_POP: 272 | default: 273 | ret = 0; 274 | break; 275 | } 276 | 277 | return ret; 278 | } 279 | 280 | int node_bio_free(BIO *bio) { 281 | if (bio == NULL) 282 | return 0; 283 | 284 | if (BIO_get_shutdown(bio)) { 285 | if (BIO_get_init(bio) && BIO_get_data(bio) != NULL) { 286 | node_bio* nbio = BIO_get_data(bio); 287 | free_empty(nbio); 288 | BIO_set_data(bio, NULL); 289 | } 290 | } 291 | 292 | return 1; 293 | } 294 | 295 | int main(int arc, char *argv[]) { 296 | printf("BIO in memory Node.js PEM_read_bio_PrivateKey issue\n"); 297 | BIO_METHOD *method; 298 | BIO *file_bio; 299 | BIO *in_mem_bio; 300 | 301 | file_bio = BIO_new_file("./rsa_private.pem", "r"); 302 | unsigned char data[4096]; 303 | int length = BIO_read(file_bio, data, sizeof(data)); 304 | 305 | // Setup the functions for the in-mem bio. 306 | method = BIO_meth_new(BIO_TYPE_MEM, "In-Memory BIO"); 307 | BIO_meth_set_read(method, read); 308 | BIO_meth_set_write(method, write); 309 | BIO_meth_set_ctrl(method, ctrl); 310 | BIO_meth_set_destroy(method, node_bio_free); 311 | 312 | in_mem_bio = BIO_new(method); 313 | char buf_data[length]; 314 | buffer buf = {0, 0, 0, NULL, buf_data}; 315 | node_bio nbio = {1024, 0, 0, -1, &buf}; 316 | // Attach our node_bio to the BIO. 317 | BIO_set_data(in_mem_bio, (void*)&nbio); 318 | BIO_set_mem_eof_return(in_mem_bio, 0); 319 | int written = BIO_write(in_mem_bio, data, length); 320 | 321 | EVP_PKEY* key = PEM_read_bio_PrivateKey(in_mem_bio, NULL, NULL, "undefined"); 322 | if (key) 323 | printf("read private key successfully\n"); 324 | else 325 | printf("cound not read private key!\n"); 326 | 327 | BIO_free(in_mem_bio); 328 | BIO_free(file_bio); 329 | EVP_PKEY_free(key); 330 | BIO_meth_free(method); 331 | free(nbio.read_head->data); 332 | free(nbio.read_head); 333 | 334 | exit(EXIT_SUCCESS); 335 | } 336 | -------------------------------------------------------------------------------- /bio_read_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int arc, char *argv[]) { 6 | printf("BIO read file into char* example\n"); 7 | 8 | BIO* bio = BIO_new_file("./rsa_private.pem", "r"); 9 | char* data = (char*) malloc(sizeof(char) * 1679); 10 | if (BIO_read(bio, data, 1679)) { 11 | printf("data: %s\n", data); 12 | } 13 | 14 | free(data); 15 | BIO_free(bio); 16 | exit(EXIT_SUCCESS); 17 | } 18 | -------------------------------------------------------------------------------- /bio_ssl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | long bio_callback(BIO *b, 9 | int oper, 10 | const char *argp, 11 | size_t len, 12 | int argi, 13 | long argl, 14 | int ret, 15 | size_t *processed) { 16 | printf("bio_callback[bio_method_name=%s, operation=%d]\n", BIO_method_name(b), oper); 17 | return ret; 18 | } 19 | 20 | int main(int arc, char *argv[]) { 21 | 22 | ERR_load_crypto_strings(); 23 | OpenSSL_add_all_algorithms(); 24 | OPENSSL_no_config(); 25 | SSL_CTX* ctx; 26 | 27 | printf("Creating SSL_CTX...\n"); 28 | 29 | ctx = SSL_CTX_new(SSLv23_client_method()); 30 | 31 | EVP_cleanup(); 32 | CRYPTO_cleanup_all_ex_data(); 33 | ERR_free_strings(); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /cprovider.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static const OSSL_DISPATCH cprovider_dispatch_table[] = { 5 | { 0, NULL } 6 | }; 7 | 8 | int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, 9 | const OSSL_DISPATCH *in, 10 | const OSSL_DISPATCH **out, 11 | void **provctx) { 12 | printf("custom_provider_init...\n"); 13 | *out = cprovider_dispatch_table; 14 | return 1; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /decoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void print_decoder(const char* name, void* data) { 13 | OSSL_DECODER* decoder = (OSSL_DECODER*) data; 14 | printf("name: %s\n", name); 15 | printf("properties: %s\n", OSSL_DECODER_get0_properties(decoder)); 16 | #if 0 17 | printf("nr: %d\n", OSSL_DECODER_number(decoder)); 18 | #endif 19 | } 20 | 21 | void print_decoders(OSSL_DECODER* decoder, void* data) { 22 | OSSL_DECODER_names_do_all(decoder, print_decoder, decoder); 23 | } 24 | 25 | void print_keymgmt(EVP_KEYMGMT* keymgmt, void* arg) { 26 | #if 0 27 | printf("keymgmt name: %s, nr: %d\n", EVP_KEYMGMT_get0_name(keymgmt), 28 | EVP_KEYMGMT_number(keymgmt)); 29 | #else 30 | printf("keymgmt name: %s\n", EVP_KEYMGMT_get0_name(keymgmt)); 31 | #endif 32 | } 33 | 34 | int main(int arc, char *argv[]) { 35 | printf("OpenSSL decoder example\n"); 36 | OSSL_PROVIDER* provider; 37 | provider = OSSL_PROVIDER_load(NULL, "default"); 38 | OSSL_LIB_CTX* libctx = OSSL_LIB_CTX_new(); 39 | 40 | printf("KEY Management info:\n"); 41 | EVP_KEYMGMT_do_all_provided(libctx, print_keymgmt, NULL); 42 | 43 | printf("Decoder info:\n"); 44 | OSSL_DECODER_do_all_provided(libctx, print_decoders, NULL); 45 | 46 | OSSL_DECODER* der_decoder = OSSL_DECODER_fetch(libctx, "der", NULL); 47 | #if 0 48 | printf("der_decoder nr: %d\n", OSSL_DECODER_number(der_decoder)); 49 | #endif 50 | 51 | OSSL_DECODER* pem_decoder = OSSL_DECODER_fetch(libctx, "RSA", 52 | "provider=default,fips=yes,input=pem"); 53 | #if 0 54 | printf("pem_decoder nr: %d\n", OSSL_DECODER_number(pem_decoder)); 55 | #endif 56 | OSSL_DECODER_names_do_all(pem_decoder, print_decoder, pem_decoder); 57 | 58 | OSSL_DECODER_CTX* decoder_ctx = OSSL_DECODER_CTX_new(); 59 | OSSL_DECODER_CTX_add_decoder(decoder_ctx, der_decoder); 60 | 61 | BIO* bio = BIO_new_file("./rsa_private.pem", "r"); 62 | int ret = OSSL_DECODER_from_bio(decoder_ctx, bio); 63 | if (ret != 0) 64 | printf("OSSL_DECODER_from_bio returned: %d\n", ret); 65 | 66 | ERR_print_errors_fp(stdout); 67 | 68 | BIO_free(bio); 69 | OSSL_DECODER_CTX_free(decoder_ctx); 70 | OSSL_DECODER_free(der_decoder); 71 | OSSL_DECODER_free(pem_decoder); 72 | OSSL_PROVIDER_unload(provider); 73 | exit(EXIT_SUCCESS); 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /digest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void handleErrors(void); 8 | 9 | int main(int arc, char *argv[]) { 10 | /* Load the human readable error strings for libcrypto */ 11 | ERR_load_crypto_strings(); 12 | 13 | /* Load all digest and cipher algorithms */ 14 | OpenSSL_add_all_algorithms(); 15 | 16 | /* Load config file, and other important initialisation */ 17 | OPENSSL_no_config(); 18 | 19 | EVP_MD_CTX* mdctx = NULL; 20 | const EVP_MD* md = NULL; 21 | 22 | char msg1[] = "Bajje\n"; 23 | char msg2[] = "Digest....\n"; 24 | unsigned char md_value[EVP_MAX_MD_SIZE]; 25 | md = EVP_get_digestbyname("SHA256"); 26 | unsigned int md_len = 0; 27 | int i = 0;; 28 | 29 | // Create a Message Digest Context for the operations 30 | mdctx = EVP_MD_CTX_new(); 31 | ENGINE* engine = NULL; 32 | // Sets up the Message Digest Context to be used with the engine, in this case 33 | // NULL which means the default implmentation for the Message Digest Type will be used 34 | printf("Message digest type: %d\n", EVP_MD_type(md)); 35 | EVP_DigestInit_ex(mdctx, md, engine); 36 | // Hash the passed in message and add it to mdctx->md_data 37 | EVP_DigestUpdate(mdctx, msg1, strlen(msg1)); 38 | // This can be done any number of times 39 | EVP_DigestUpdate(mdctx, msg2, strlen(msg2)); 40 | 41 | EVP_DigestFinal_ex(mdctx, md_value, &md_len); 42 | 43 | const EVP_MD* md_ptr = EVP_MD_CTX_md(mdctx); 44 | printf("md_ptr = %lu\n", EVP_MD_meth_get_flags(md_ptr)); 45 | 46 | int r = EVP_MD_CTX_test_flags(mdctx, EVP_MD_FLAG_DIGALGID_MASK); 47 | printf("r =%d\n", r); 48 | 49 | 50 | printf("md_len: %d\n", md_len); 51 | printf("EVP_MD_CTX_size: %d\n", EVP_MD_CTX_size(mdctx)); 52 | printf("EVP_MD_size: %d\n", EVP_MD_size(md)); 53 | 54 | EVP_MD_CTX_free(mdctx); 55 | printf("Digest is: "); 56 | for (i = 0; i < md_len; i++) { 57 | printf("%02x", md_value[i]); 58 | } 59 | printf("\n"); 60 | 61 | /* Removes all digests and ciphers */ 62 | EVP_cleanup(); 63 | 64 | /* if you omit the next, a small leak may be left when you make use of the BIO (low level API) for e.g. base64 transformations */ 65 | CRYPTO_cleanup_all_ex_data(); 66 | 67 | /* Remove error strings */ 68 | ERR_free_strings(); 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /distribution.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char** argv) { 5 | //auto dis = std::uniform_int_distribution(0, 255); 6 | // 7 | std::random_device rd; //Will be used to obtain a seed for the random number engine 8 | std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd() 9 | std::uniform_int_distribution<> dis(0, 255); 10 | 11 | for (int n=0; n<10; ++n) 12 | //Use dis to transform the random unsigned int generated by gen into an int in [0, 255] 13 | std::cout << dis(gen) << ' '; 14 | 15 | std::cout << '\n'; 16 | } 17 | -------------------------------------------------------------------------------- /dsa.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void error_and_exit(const char* msg) { 10 | printf("%s\n", msg); 11 | char buf[256]; 12 | int err = ERR_get_error(); 13 | ERR_error_string_n(err, buf, sizeof(buf)); 14 | printf("errno: %d, %s\n", err, buf); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int main(int arc, char *argv[]) { 19 | printf("DSA example\n"); 20 | 21 | OSSL_PROVIDER* provider; 22 | provider = OSSL_PROVIDER_load(NULL, "default"); 23 | 24 | // 512 was the original value with caused a "bad ffc parameters" error 25 | int modulus_bits = 2048; 26 | uint32_t divisor_bits = 256; 27 | 28 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); 29 | if (ctx == NULL) { 30 | error_and_exit("Could not create a context for DSA"); 31 | } 32 | 33 | if (EVP_PKEY_paramgen_init(ctx) <= 0) { 34 | error_and_exit("Could not initialize the DSA context"); 35 | } 36 | 37 | if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, modulus_bits) <= 0) { 38 | error_and_exit("EVP_PKEY_CTX_set_dsa_paramgen_bits failed"); 39 | } 40 | 41 | if (EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, 42 | EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, 43 | divisor_bits, NULL) <= 0) { 44 | error_and_exit("EVP_PKEY_CTX_ctrl failed"); 45 | } 46 | 47 | EVP_PKEY* raw_params = NULL; 48 | if (EVP_PKEY_paramgen(ctx, &raw_params) <= 0) { 49 | error_and_exit("EVP_PKEY_CTX_set_rsa_keygen_bits failed"); 50 | } 51 | 52 | EVP_PKEY_CTX_free(ctx); 53 | EVP_PKEY_free(raw_params); 54 | 55 | OSSL_PROVIDER_unload(provider); 56 | exit(EXIT_SUCCESS); 57 | } 58 | -------------------------------------------------------------------------------- /dsa_private_encrypted_1025.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIBvTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIqTW00yecdxMCAggA 3 | MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBKgO4UF0LfCkPyS+iCvSrtBIIB 4 | YD3W6FyEZ97/crnoyRqjPUtr2Mm4KJMtaB5ZiGFzZEzd6AH7N/dbtAAMIibtsjmd 5 | RYdIptpET6xTpUhM8TvpULyYaZnhZJKTpVUrTVdvFTS3DYDutu7aWRLTrle6LzcY 6 | XpIppeP8ZmYFdRBQxhF+KoDsP4O0QA+vWl2W2VmRfr+sK9R+qV89w0YMjEWHsYY+ 7 | VZsDbJBGKkj9gzIvxIsRyack/+RsbiSDrh6WTw+D0jrX/IMbgPjvYfBFhpxGC7zR 8 | hDn9r3JaO2KdHh9kMtvQfshA1n636kb0X6ewY57BhEs3J4hpMg46c6YFry94to24 9 | jxl5KutM0CFea7mYGtNf6WJXBsm7JSW03kjlqYoZGK43KNgZhzKAsXaNkoRkA5cw 10 | BzGfgmG6dHTpeAY9G4vM4inhCmGFA8Tx189g+xzRv16uFXRb8WFIllne1fEFaXRr 11 | 1Rz2G6SPJkA3fsrl8zUIB0Y= 12 | -----END ENCRYPTED PRIVATE KEY----- 13 | -------------------------------------------------------------------------------- /ec-keygen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #if defined(__FreeBSD__) 12 | #include 13 | #endif 14 | #include 15 | #include 16 | 17 | /** 18 | * Some OSes like Linux and Mac OSX treat pthread_t like an integral value. 19 | * Others, like FreeBSD, treat pthread_t like an opaque type. POSIX states that 20 | * the pthread_t type is opaque and doesn't provide a portable means of getting 21 | * some sort of meaningful identifier for human consumption. 22 | * 23 | * Attempt to obtain a pthread ID for human consumption using a non-POSIX 24 | * compliant interface. 25 | */ 26 | static unsigned int 27 | my_pthread_id(void) 28 | { 29 | 30 | #if defined(__FreeBSD__) 31 | return (unsigned int)(pthread_getthreadid_np()); 32 | #else 33 | return (unsigned int)(pthread_self()); 34 | #endif 35 | } 36 | 37 | void error_and_exit(const char* msg) { 38 | printf("%s\n", msg); 39 | char buf[256]; 40 | int err = ERR_get_error(); 41 | ERR_error_string_n(err, buf, sizeof(buf)); 42 | printf("errno: %d, %s\n", err, buf); 43 | } 44 | 45 | pthread_mutex_t pkey_lock; 46 | 47 | void* get_ec_key(void* args) { 48 | EVP_PKEY* pkey = (EVP_PKEY*) args; 49 | printf("[%u] get_ec_keys: pkey: %p\n", my_pthread_id(), pkey); 50 | pthread_mutex_lock(&pkey_lock); 51 | const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey); 52 | pthread_mutex_unlock(&pkey_lock); 53 | printf("[%u] get_ec_keys: ec_key: %p\n", my_pthread_id(), ec_key); 54 | pthread_exit(NULL); 55 | } 56 | 57 | void* get_pkcs8(void* args) { 58 | EVP_PKEY* pkey = (EVP_PKEY*) args; 59 | printf("[%u] get_pkcs8: pkey: %p\n", my_pthread_id(), pkey); 60 | 61 | pthread_mutex_lock(&pkey_lock); 62 | PKCS8_PRIV_KEY_INFO* pkcs8 = EVP_PKEY2PKCS8(pkey); 63 | pthread_mutex_unlock(&pkey_lock); 64 | BIO* pkcs8_bio = BIO_new(BIO_s_mem()); 65 | if (i2d_PKCS8_PRIV_KEY_INFO_bio(pkcs8_bio, pkcs8) <= 0) { 66 | error_and_exit("Could not convert to PKCS8 format"); 67 | } 68 | printf("[%u] get_pkcs8: pkcs8: %p\n", my_pthread_id(), pkcs8); 69 | pthread_exit(NULL); 70 | } 71 | 72 | int main(int arc, char *argv[]) { 73 | //const char* curve_name = "secp384r1"; 74 | const char* curve_name = "P-384"; 75 | printf("Elliptic Curve keygen (%s) example \n", curve_name); 76 | int curve_nid = EC_curve_nist2nid(curve_name); 77 | if (curve_nid == NID_undef) { 78 | // try converting the shortname (sn) to nid (numberic id) 79 | curve_nid = OBJ_sn2nid(curve_name); 80 | } 81 | printf("curve_nid of %s: %d\n", curve_name, curve_nid); 82 | 83 | // The last argument is the ENGINE*. 84 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); 85 | // The following function is for generating parameters 86 | if (EVP_PKEY_paramgen_init(ctx) <= 0) { 87 | error_and_exit("Could not initialize the parameters for key generation"); 88 | } 89 | 90 | // Set the curve as there are no default curves. 91 | if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_nid) <= 0) { 92 | error_and_exit("Could not set the param curve nid"); 93 | } 94 | 95 | // Set the parameter encoding which can be either OPENSSL_EC_EXPLICIT_CURVE 96 | // or OPENSSL_EC_NAMED_CURVE. The default for OpenSSL 3.x is named curve 97 | printf("Set ec_param_encoding to %d\n", OPENSSL_EC_NAMED_CURVE); 98 | int ret = EVP_PKEY_CTX_set_ec_param_enc(ctx, OPENSSL_EC_NAMED_CURVE); 99 | if (ret <= 0) { 100 | printf("EVP_PKEY_CTX_set_ec_param_enc retuned: %d\n", ret); 101 | error_and_exit("EVP_PKEY_CTX_set_ec_param_enc failed"); 102 | } 103 | 104 | EVP_PKEY* params = NULL; 105 | // Generate the parameters. 106 | if (EVP_PKEY_paramgen(ctx, ¶ms) <= 0) { 107 | error_and_exit("Could not generate the paremeters"); 108 | } 109 | 110 | EVP_PKEY_CTX* key_ctx = EVP_PKEY_CTX_new(params, NULL); 111 | 112 | if (EVP_PKEY_keygen_init(key_ctx) <= 0) { 113 | error_and_exit("Could not initialize the keygen context the paremeters"); 114 | } 115 | 116 | EVP_PKEY* pkey = NULL; 117 | if (EVP_PKEY_keygen(key_ctx, &pkey) <= 0) { 118 | error_and_exit("Could not generate the private key"); 119 | } 120 | 121 | printf("created EVP_PKEY, now create threads and pass reference as args\n"); 122 | 123 | if (pthread_mutex_init(&pkey_lock, NULL) != 0) { 124 | printf("pthread_mutext_init failed\n"); 125 | return 1; 126 | } 127 | pthread_t get_pkcs8_t; 128 | 129 | pthread_t get_ec_key_t; 130 | 131 | pthread_create(&get_pkcs8_t, NULL, get_pkcs8, pkey); 132 | pthread_setname_np(get_pkcs8_t, "getpkcs8 thread"); 133 | pthread_create(&get_ec_key_t, NULL, get_ec_key, pkey); 134 | pthread_setname_np(get_ec_key_t, "get_ec_key thread"); 135 | 136 | pthread_join(get_pkcs8_t, NULL); 137 | pthread_join(get_ec_key_t, NULL); 138 | pthread_mutex_destroy(&pkey_lock); 139 | 140 | printf("all done in main...\n"); 141 | EVP_PKEY_free(pkey); 142 | EVP_PKEY_CTX_free(ctx); 143 | EVP_PKEY_CTX_free(key_ctx); 144 | exit(EXIT_SUCCESS); 145 | } 146 | -------------------------------------------------------------------------------- /ec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void error_and_exit(const char* msg) { 11 | printf("%s\n", msg); 12 | char buf[256]; 13 | int err = ERR_get_error(); 14 | ERR_error_string_n(err, buf, sizeof(buf)); 15 | printf("errno: %d, %s\n", err, buf); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | int main(int arc, char *argv[]) { 20 | printf("Elliptic Curve example\n"); 21 | 22 | const char* curve_name = "secp256k1"; 23 | int curve_nid = EC_curve_nist2nid(curve_name); 24 | if (curve_nid == NID_undef) { 25 | // try converting the shortname (sn) to nid (numberic id) 26 | curve_nid = OBJ_sn2nid(curve_name); 27 | } 28 | printf("curve_nid of %s: %d\n", curve_name, curve_nid); 29 | 30 | // The last argument is the ENGINE*. 31 | // 32 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); 33 | // The following function is for generating parameters 34 | if (EVP_PKEY_paramgen_init(ctx) <= 0) { 35 | error_and_exit("Could not initialize the parameters for key generation"); 36 | } 37 | 38 | // Set the curve as there are no default curves. 39 | if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_nid) <= 0) { 40 | error_and_exit("Could not set the param curve nid"); 41 | } 42 | // Set the parameter encoding which can be either OPENSSL_EC_EXPLICIT_CURVE 43 | // or OPENSSL_EC_NAMED_CURVE. The default for OpenSSL 3.x is named curve 44 | int ret = EVP_PKEY_CTX_set_ec_param_enc(ctx, OPENSSL_EC_NAMED_CURVE); 45 | if (ret <= 0) { 46 | printf("EVP_PKEY_CTX_set_ec_param_enc retuned: %d\n", ret); 47 | error_and_exit("EVP_PKEY_CTX_set_ec_param_enc failed"); 48 | } 49 | 50 | EVP_PKEY* params = NULL; 51 | // Generate the parameters. 52 | if (EVP_PKEY_paramgen(ctx, ¶ms) <= 0) { 53 | error_and_exit("Could not generate the paremeters"); 54 | } 55 | 56 | EVP_PKEY_CTX* key_ctx = EVP_PKEY_CTX_new(params, NULL); 57 | 58 | if (EVP_PKEY_keygen_init(key_ctx) <= 0) { 59 | error_and_exit("Could not initialize the keygen context the paremeters"); 60 | } 61 | 62 | EVP_PKEY* pkey = NULL; 63 | if (EVP_PKEY_keygen(key_ctx, &pkey) <= 0) { 64 | error_and_exit("Could not generate the private key"); 65 | } 66 | 67 | // The '1' indicates that the ref count will be decremented so it must be 68 | // freed by us. Use EVP_PKEY_get0_EC_KEY to avoid this. 69 | EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey); 70 | const BIGNUM* b = EC_KEY_get0_private_key(ec_key); 71 | BIO* out = BIO_new(BIO_s_mem()); 72 | 73 | int len = PEM_write_bio_ECPrivateKey(out, ec_key, NULL, NULL, 0, NULL, NULL); 74 | if (len <= 0) { 75 | error_and_exit("Could not write the private key"); 76 | } 77 | BUF_MEM* bptr; 78 | BIO_get_mem_ptr(out, &bptr); 79 | printf("%s\n", bptr->data); 80 | 81 | BIO* pub_out = BIO_new(BIO_s_mem()); 82 | len = PEM_write_bio_EC_PUBKEY(pub_out, ec_key); 83 | if (len <= 0) { 84 | error_and_exit("Could not write the private key"); 85 | } 86 | BIO_get_mem_ptr(pub_out, &bptr); 87 | printf("%s\n", bptr->data); 88 | 89 | const EC_GROUP* group = EC_KEY_get0_group(ec_key); 90 | int order = EC_GROUP_order_bits(group); 91 | printf("Group order: %d\n", order); 92 | 93 | const EC_POINT* generator = EC_GROUP_get0_generator(group); 94 | 95 | EVP_PKEY_CTX_free(ctx); 96 | exit(EXIT_SUCCESS); 97 | } 98 | -------------------------------------------------------------------------------- /engine.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Legacy concept for third-party loadable code. 3 | * 4 | * Per the upstream docs, "use providers instead". 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | static const char* id = "test-engine"; 12 | static const char* name = "OpenSSL Engine example"; 13 | 14 | /* 15 | * The OpenSSL library will perform checks to verify that the 16 | * Engine is compatible with this version of OpenSSL and finish 17 | * with calling this function which is specified using the 18 | * IMPLEMENT_DYNAMIC_BIND_FN macro. 19 | */ 20 | static int bind(ENGINE* e, const char* id) { 21 | if (!ENGINE_set_id(e, id)) { 22 | fprintf(stderr, "Filed to set engine id to %s\n", id); 23 | return 0; 24 | } 25 | if (!ENGINE_set_name(e, name)) { 26 | fprintf(stderr, "Filed to set engine name to %s\n", name); 27 | return 0; 28 | } 29 | return 1; 30 | } 31 | 32 | IMPLEMENT_DYNAMIC_BIND_FN(bind) 33 | IMPLEMENT_DYNAMIC_CHECK_FN() 34 | -------------------------------------------------------------------------------- /err.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int arc, char *argv[]) { 6 | printf("OpenSSL Error Example\n"); 7 | OSSL_PROVIDER* provider; 8 | provider = OSSL_PROVIDER_load(NULL, "default"); 9 | 10 | int example_lib = ERR_get_next_error_library(); 11 | int reason_1 = 1; 12 | int reason_2 = 2; 13 | int reason_3 = 3; 14 | 15 | // Register the library the errors belong to 16 | ERR_STRING_DATA str_lib = { ERR_PACK(example_lib, 0, 0), "example lib" }; 17 | int ret = ERR_load_strings(example_lib, &str_lib); 18 | 19 | // Register the first error 20 | const ERR_STRING_DATA str_reason_1 = { ERR_PACK(example_lib, 0, reason_1), "something bad happened 1"}; 21 | ERR_load_strings_const(&str_reason_1); 22 | int lib_nr = ERR_GET_LIB(str_reason_1.error); 23 | printf("lib_nr: %d\n", lib_nr); 24 | 25 | // Register the second error 26 | const ERR_STRING_DATA str_reason_2= { ERR_PACK(example_lib, 0, reason_2), "something bad happened 2"}; 27 | ERR_load_strings_const(&str_reason_2); 28 | 29 | ERR_raise(example_lib, reason_1); 30 | int error = ERR_get_error(); 31 | printf("%s:%s\n", ERR_lib_error_string(error), ERR_reason_error_string(error)); 32 | 33 | ERR_raise_data(example_lib, reason_2, "details go here..."); 34 | ERR_print_errors_fp(stdout); 35 | 36 | ERR_raise_data(example_lib, reason_2, "before setting mark"); 37 | int mark = ERR_set_mark(); 38 | printf("mark: %d\n", mark); 39 | if (reason_1 == 1) { 40 | // Imaging the following line was in a function and we don't want these 41 | // error to be propagated, for example we might be able to call a different 42 | // function and still continue. 43 | ERR_raise_data(example_lib, reason_1, "after setting mark"); 44 | mark = ERR_pop_to_mark(); 45 | printf("popped: %d\n", mark); 46 | } 47 | 48 | mark = ERR_clear_last_mark(); 49 | printf("cleared: %d\n", mark); 50 | 51 | ERR_print_errors_fp(stdout); 52 | 53 | OSSL_PROVIDER_unload(provider); 54 | 55 | exit(EXIT_SUCCESS); 56 | } 57 | -------------------------------------------------------------------------------- /evp-pkey.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../openssl/include/crypto/evp.h" 11 | #include "../openssl/include/crypto/asn1.h" 12 | #include "../openssl/crypto/evp/evp_local.h" 13 | 14 | EVP_PKEY* create_evp_pkey(); 15 | 16 | void error_and_exit(const char* msg) { 17 | printf("%s\n", msg); 18 | char buf[256]; 19 | int err = ERR_get_error(); 20 | ERR_error_string_n(err, buf, sizeof(buf)); 21 | printf("errno: %d, %s\n", err, buf); 22 | } 23 | 24 | int main(int arc, char *argv[]) { 25 | printf("EVP_PKEY exploration\n"); 26 | EVP_PKEY* pkey = create_evp_pkey(); 27 | 28 | printf("Before downgrade of EVP_PKEY:\n"); 29 | printf("evp_pkey_is_legacy: %s\n", evp_pkey_is_legacy(pkey) ? "true" : "false"); 30 | printf("evp_pkey->ameth: %p\n", pkey->ameth); 31 | printf("evp_pkey->keymgmt: %p\n", pkey->keymgmt); 32 | printf("evp_pkey->keydata: %p\n", pkey->keydata); 33 | printf("evp_pkey->keymgmt->prov: %s\n", pkey->keymgmt->prov); 34 | printf("evp_pkey->keymgmt->prov name: %s\n", OSSL_PROVIDER_name(pkey->keymgmt->prov)); 35 | 36 | // This will call evp_pkey_downgrade 37 | EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey); 38 | 39 | printf("\nAfter downgrade of EVP_PKEY:\n"); 40 | printf("evp_pkey_is_legacy: %s\n", evp_pkey_is_legacy(pkey) ? "true" : "false"); 41 | printf("evp_pkey->keymgmt: %p\n", pkey->keymgmt); 42 | printf("evp_pkey->keydata: %p\n", pkey->keydata); 43 | printf("evp_pkey->ameth->pkey_id: %d\n", pkey->ameth->pkey_id); 44 | printf("evp_pkey->ameth->pem_str: %s\n", pkey->ameth->pem_str); 45 | printf("evp_pkey->ameth->info: %s\n", pkey->ameth->info); 46 | 47 | EVP_PKEY_free(pkey); 48 | exit(EXIT_SUCCESS); 49 | } 50 | 51 | EVP_PKEY* create_evp_pkey() { 52 | const char* curve_name = "P-384"; 53 | int curve_nid = EC_curve_nist2nid(curve_name); 54 | if (curve_nid == NID_undef) { 55 | // try converting the shortname (sn) to nid (numberic id) 56 | curve_nid = OBJ_sn2nid(curve_name); 57 | } 58 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); 59 | if (EVP_PKEY_paramgen_init(ctx) <= 0) { 60 | error_and_exit("Could not initialize the parameters for key generation"); 61 | } 62 | if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_nid) <= 0) { 63 | error_and_exit("Could not set the param curve nid"); 64 | } 65 | int ret = EVP_PKEY_CTX_set_ec_param_enc(ctx, OPENSSL_EC_NAMED_CURVE); 66 | if (ret <= 0) { 67 | printf("EVP_PKEY_CTX_set_ec_param_enc retuned: %d\n", ret); 68 | error_and_exit("EVP_PKEY_CTX_set_ec_param_enc failed"); 69 | } 70 | EVP_PKEY* params = NULL; 71 | if (EVP_PKEY_paramgen(ctx, ¶ms) <= 0) { 72 | error_and_exit("Could not generate the paremeters"); 73 | } 74 | EVP_PKEY_CTX* key_ctx = EVP_PKEY_CTX_new(params, NULL); 75 | if (EVP_PKEY_keygen_init(key_ctx) <= 0) { 76 | error_and_exit("Could not initialize the keygen context the paremeters"); 77 | } 78 | EVP_PKEY* pkey = NULL; 79 | if (EVP_PKEY_keygen(key_ctx, &pkey) <= 0) { 80 | error_and_exit("Could not generate the private key"); 81 | } 82 | EVP_PKEY_CTX_free(ctx); 83 | EVP_PKEY_CTX_free(key_ctx); 84 | return pkey; 85 | } 86 | -------------------------------------------------------------------------------- /fips-provider.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void error_and_exit(const char* msg) { 9 | printf("%s\n", msg); 10 | char buf[256]; 11 | int err = ERR_get_error(); 12 | ERR_error_string_n(err, buf, sizeof(buf)); 13 | printf("errno: %d, %s\n", err, buf); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | /* 18 | * This needs to be run using OPENSSL_CONF so that the OpenSSL configuration 19 | * file in this directory is used: 20 | * 21 | * $ env OPENSSL_CONF=$PWD/openssl.cnf OPENSSL_MODULES=path/to/ossl-modules ./fips-provider 22 | * 23 | * For example: 24 | * $ env OPENSSL_CONF=$PWD/openssl.cnf OPENSSL_MODULES=/home/danielbevenius/work/security/openssl_build_master/lib/ossl-modules ./fips-provider 25 | */ 26 | int main(int argc, char** argv) { 27 | printf("FIPS Provider example\n"); 28 | OSSL_PROVIDER* fips; 29 | EVP_MD* sha256 = NULL; 30 | 31 | //CONF_modules_load_file("./openssl.cnf", "openssl_conf", 0); 32 | 33 | fips = OSSL_PROVIDER_load(NULL, "fips"); 34 | if (fips == NULL) { 35 | printf("Failed to load FIPS provider\n"); 36 | int err = ERR_get_error(); 37 | char buf[256]; 38 | ERR_error_string_n(err, buf, sizeof(buf)); 39 | printf("errno: %d, %s\n", err, buf); 40 | exit(EXIT_FAILURE); 41 | } 42 | // EVP_default_properties_is_fips_enabled should return 1 if FIPS is enabled 43 | int r = EVP_default_properties_is_fips_enabled(NULL); 44 | printf("FIPS is enabled (%d): %s\n", r, r == 1 ? "true": "false"); 45 | 46 | if (EVP_default_properties_enable_fips(NULL, 1)) { 47 | printf("enabled fips\n"); 48 | } else { 49 | error_and_exit("Failed to enable fips\n"); 50 | } 51 | 52 | // EVP_default_properties_is_fips_enabled should return 1 if FIPS is enabled 53 | r = EVP_default_properties_is_fips_enabled(NULL); 54 | printf("FIPS is enabled (%d): %s\n", r, r == 1 ? "true": "false"); 55 | 56 | sha256 = EVP_MD_fetch(NULL, "SHA2-256", NULL); 57 | printf("Provider name for sha256: %s\n", 58 | OSSL_PROVIDER_get0_name(EVP_MD_get0_provider(sha256))); 59 | 60 | OSSL_PROVIDER_unload(fips); 61 | exit(EXIT_SUCCESS); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /fips.cnf: -------------------------------------------------------------------------------- 1 | [fipsinstall] 2 | activate = 1 3 | install-version = 1 4 | conditional-errors = 1 5 | security-checks = 1 6 | module-mac = C2:B3:E8:E4:CB:F9:DF:4F:AC:1F:80:7A:10:1C:83:7D:01:E7:9B:54:65:7C:B0:4A:25:08:C4:1F:4F:51:F1:B8 7 | install-mac = 41:9C:38:C2:8F:59:09:43:2C:AA:2F:58:36:2D:D9:04:F9:6C:56:8B:09:E0:18:3A:2E:D6:CC:69:05:04:E1:11 8 | install-status = INSTALL_SELF_TEST_KATS_RUN 9 | -------------------------------------------------------------------------------- /generator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | int main() { 9 | std::random_device rd; //Will be used to obtain a seed for the random number engine 10 | std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd() 11 | uint8_t reset_token[10]; 12 | std::generate(std::begin(reset_token), std::end(reset_token), gen); 13 | for (int i = 0; i < 10; i++) { 14 | cout << reset_token[i] << '\n'; 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void print_error() { 11 | char buf[256]; 12 | int err = ERR_get_error(); 13 | ERR_error_string_n(err, buf, sizeof(buf)); 14 | printf("errno: %d, %s\n", err, buf); 15 | } 16 | 17 | struct something_st { 18 | char* name; 19 | }; 20 | typedef struct something_st SOMETHING; 21 | 22 | struct lhash_st_SOMETHING { 23 | union lh_SOMETHING_dummy { void* d1; unsigned long d2; int d3; } dummy; 24 | }; 25 | 26 | long unsigned int something_hash(const SOMETHING* s) { 27 | return OPENSSL_LH_strhash(s->name); 28 | } 29 | 30 | int something_compare(const SOMETHING* s1, const SOMETHING* s2) { 31 | return strcmp(s1->name, s2->name); 32 | } 33 | 34 | #ifndef __unused 35 | #define __unused __attribute__((unused)) 36 | #endif 37 | 38 | //DEFINE_LHASH_OF(SOMETHING); 39 | //The above will generate the following: 40 | 41 | // lh_SOMETHING_new is used to create a hash table. It takes a hash function 42 | // and a compare function which are defined above. 43 | static __unused 44 | inline struct lhash_st_SOMETHING* lh_SOMETHING_new( 45 | unsigned long (*hfn)(const SOMETHING*), 46 | int (*cfn)(const SOMETHING*, const SOMETHING*)) { 47 | return (struct lhash_st_SOMETHING*) 48 | OPENSSL_LH_new((OPENSSL_LH_HASHFUNC)hfn, (OPENSSL_LH_COMPFUNC)cfn); 49 | } 50 | // Notice that the return type if struct lhash_st_SOMETHING* which can then 51 | // be used to call the other functions below: 52 | 53 | // So to insert we pass our hash table that we created above and a pointer 54 | // to struct somthing_st (SOMETHING) to insert. 55 | // 56 | static __unused 57 | inline SOMETHING *lh_SOMETHING_insert(struct lhash_st_SOMETHING *lh, SOMETHING *d) { 58 | return (SOMETHING *)OPENSSL_LH_insert((OPENSSL_LHASH *)lh, d); 59 | } 60 | 61 | // Get/retrieve a value from the hash table: 62 | static __unused 63 | inline SOMETHING *lh_SOMETHING_retrieve(struct lhash_st_SOMETHING *lh, const SOMETHING *d) { 64 | return (SOMETHING *)OPENSSL_LH_retrieve((OPENSSL_LHASH *)lh, d); 65 | } 66 | 67 | // Get the number of entries in the hash table 68 | static __unused 69 | inline unsigned long lh_SOMETHING_num_items(struct lhash_st_SOMETHING *lh) { 70 | return OPENSSL_LH_num_items((OPENSSL_LHASH *)lh); 71 | } 72 | 73 | static __unused 74 | inline void lh_SOMETHING_free(struct lhash_st_SOMETHING* lh) { 75 | OPENSSL_LH_free((OPENSSL_LHASH *)lh); 76 | } 77 | 78 | static __unused 79 | inline void lh_SOMETHING_flush(struct lhash_st_SOMETHING *lh) { 80 | OPENSSL_LH_flush((OPENSSL_LHASH *)lh); 81 | } 82 | 83 | static __unused 84 | inline SOMETHING *lh_SOMETHING_delete(struct lhash_st_SOMETHING *lh, const SOMETHING *d) { 85 | return (SOMETHING *)OPENSSL_LH_delete((OPENSSL_LHASH *)lh, d); 86 | } 87 | 88 | static __unused 89 | inline int lh_SOMETHING_error(struct lhash_st_SOMETHING *lh) { 90 | return OPENSSL_LH_error((OPENSSL_LHASH *)lh); 91 | } 92 | 93 | static __unused 94 | inline void lh_SOMETHING_node_stats_bio(const struct lhash_st_SOMETHING *lh, BIO *out) { 95 | OPENSSL_LH_node_stats_bio((const OPENSSL_LHASH *)lh, out); 96 | } 97 | 98 | static __unused 99 | inline void lh_SOMETHING_node_usage_stats_bio(const struct lhash_st_SOMETHING *lh, BIO *out) { 100 | OPENSSL_LH_node_usage_stats_bio((const OPENSSL_LHASH *)lh, out); 101 | } 102 | 103 | static __unused 104 | inline void lh_SOMETHING_stats_bio(const struct lhash_st_SOMETHING *lh, BIO *out) { 105 | OPENSSL_LH_stats_bio((const OPENSSL_LHASH *)lh, out); 106 | } 107 | 108 | static __unused 109 | inline unsigned long lh_SOMETHING_get_down_load(struct lhash_st_SOMETHING *lh) { 110 | return OPENSSL_LH_get_down_load((OPENSSL_LHASH *)lh); 111 | } 112 | 113 | static __unused 114 | inline void lh_SOMETHING_set_down_load(struct lhash_st_SOMETHING *lh, unsigned long dl) { 115 | OPENSSL_LH_set_down_load((OPENSSL_LHASH *)lh, dl); 116 | } 117 | 118 | static __unused 119 | inline void lh_SOMETHING_doall(struct lhash_st_SOMETHING *lh, void (*doall)(SOMETHING *)) { 120 | OPENSSL_LH_doall((OPENSSL_LHASH *)lh, (OPENSSL_LH_DOALL_FUNC)doall); 121 | } struct lhash_st_SOMETHING; 122 | 123 | void do_all(SOMETHING* s) { 124 | printf("s->name: %s\n", s->name); 125 | } 126 | 127 | int main(int argc, char** argv) { 128 | printf("OpenSSL lhash example\n"); 129 | struct lhash_st_SOMETHING* lh = lh_SOMETHING_new(something_hash, something_compare); 130 | 131 | struct something_st first = {"first"}; 132 | SOMETHING* nothing = lh_SOMETHING_insert(lh, &first); 133 | assert(nothing == NULL); 134 | printf("Inserted: %s\n", first.name); 135 | printf("Number of items: %lu\n", lh_SOMETHING_num_items(lh)); 136 | 137 | SOMETHING* inserted = lh_SOMETHING_retrieve(lh, &first); 138 | printf("Retrieved: %s\n", inserted->name); 139 | 140 | printf("Do all:\n"); 141 | lh_SOMETHING_doall(lh, do_all); 142 | 143 | print_error(); 144 | exit(EXIT_SUCCESS); 145 | } 146 | 147 | -------------------------------------------------------------------------------- /hmac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int pass_cb(char *buf, int size, int rwflag, void *u) { 9 | int len; 10 | char *tmp; 11 | /* We'd probably do something else if 'rwflag' is 1 */ 12 | if (u) { 13 | printf("Get the password for \"%s\"\n", u); 14 | tmp = "test"; 15 | len = strlen(tmp); 16 | 17 | if (len <= 0) return 0; 18 | /* if too long, truncate */ 19 | if (len > size) len = size; 20 | memcpy(buf, tmp, len); 21 | return len; 22 | } else { 23 | return 0; 24 | } 25 | } 26 | 27 | int hmac(const char* msg, size_t m_len, char** val, size_t* vlen, EVP_PKEY* pkey); 28 | EVP_PKEY* load_private_key(const char* file); 29 | 30 | void handleErrors(void); 31 | 32 | int main(int arc, char* argv[]) { 33 | ERR_load_crypto_strings(); 34 | OpenSSL_add_all_algorithms(); 35 | OPENSSL_no_config(); 36 | 37 | EVP_PKEY* pkey = load_private_key("test.key"); 38 | 39 | char* msg = (char*) "Bajja"; 40 | size_t msg_len = strlen ((char*)msg); 41 | char* val = (char *) "val"; 42 | size_t val_len = strlen ((char*)val); 43 | 44 | int result = hmac(msg, msg_len, &val, &val_len, pkey); 45 | printf("result %d\n", result); 46 | 47 | EVP_cleanup(); 48 | CRYPTO_cleanup_all_ex_data(); 49 | ERR_free_strings(); 50 | return 0; 51 | } 52 | 53 | 54 | int hmac(const char* msg, size_t m_len, char** val, size_t* val_len, EVP_PKEY* pkey) { 55 | EVP_MD_CTX* mdctx = NULL; 56 | mdctx = EVP_MD_CTX_create(); 57 | if(!(mdctx = EVP_MD_CTX_new())) { 58 | handleErrors(); 59 | } 60 | 61 | const EVP_MD* md = EVP_get_digestbyname("SHA256"); 62 | if (md == NULL) { 63 | handleErrors(); 64 | } 65 | 66 | ENGINE* engine = NULL; 67 | int rc = EVP_DigestInit_ex(mdctx, md, engine); 68 | if (rc != 1) { 69 | handleErrors(); 70 | } 71 | 72 | // 73 | rc = EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey); 74 | return -1; 75 | 76 | } 77 | 78 | EVP_PKEY* load_private_key(const char* file) { 79 | BIO *keybio; 80 | if ((keybio = BIO_new_file(file, "r")) == NULL) { 81 | ERR_print_errors_fp(stderr); 82 | exit(0); 83 | } 84 | EVP_PKEY* pkey = PEM_read_bio_PrivateKey(keybio, NULL, pass_cb, "test key"); 85 | if (pkey == NULL) { 86 | ERR_print_errors_fp(stderr); 87 | exit(0); 88 | } 89 | return pkey; 90 | } 91 | 92 | 93 | void handleErrors(void) { 94 | ERR_print_errors_fp(stderr); 95 | abort(); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /is_fips_enabled.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * This needs to be run using OPENSSL_CONF so that the OpenSSL configuration 12 | * file in this directory is used: 13 | * 14 | * $ env OPENSSL_CONF=$PWD/openssl.cnf OPENSSL_MODULES=path/to/ossl-modules ./is_fips_enabled 15 | * 16 | * For example: 17 | * $ env OPENSSL_CONF=$PWD/openssl.cnf OPENSSL_MODULES=/home/danielbevenius/work/security/openssl_build_master/lib/ossl-modules ./is_fips_enabled 18 | */ 19 | int main(int argc, char** argv) { 20 | //CONF_modules_load_file("./openssl.cnf", "openssl_conf", 0); 21 | 22 | // EVP_default_properties_is_fips_enabled should return 1 if FIPS is enabled 23 | OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new(); 24 | OPENSSL_INIT_set_config_file_flags(settings, CONF_MFLAGS_DEFAULT_SECTION); 25 | int r = OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings); 26 | printf("Result from OPENSSL_init_crypto: %d\n", r); 27 | OPENSSL_INIT_free(settings); 28 | 29 | r = EVP_default_properties_is_fips_enabled(NULL); 30 | unsigned long e = ERR_peek_error(); 31 | if (ERR_SYSTEM_ERROR(e)) { 32 | printf("ERR_GET_REASON(e): %d\n", ERR_GET_REASON(e)); 33 | //ERR_print_errors_fp(stderr); 34 | 35 | unsigned long e = 0; 36 | const char* data; 37 | int line, flags; 38 | while ((e = ERR_get_error_all(NULL, NULL, NULL, &data, NULL)) != 0) { 39 | printf("Error nr: %d, reason: %s\n", ERR_GET_REASON(e), data); 40 | } 41 | exit(EXIT_FAILURE); 42 | } 43 | if (errno) { 44 | int error_num = errno; 45 | printf("errno: %d\n", error_num); 46 | printf("Error opening file: %s\n", strerror(error_num)); 47 | exit(EXIT_FAILURE); 48 | } 49 | const char* data = NULL; 50 | int flags = 0; 51 | unsigned long err = ERR_peek_last_error_data(&data, &flags); 52 | if (data != NULL) { 53 | printf("OpenSSL error: %s\n", ERR_reason_error_string(err)); 54 | exit(EXIT_FAILURE); 55 | } 56 | 57 | printf("Fips is enabled: %s\n", r == 1 ? "true" : "false"); 58 | 59 | exit(EXIT_SUCCESS); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /keymgmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void error_and_exit(const char* msg) { 12 | printf("%s\n", msg); 13 | char buf[256]; 14 | int err = ERR_get_error(); 15 | ERR_error_string_n(err, buf, sizeof(buf)); 16 | fprintf(stderr, "errno: %d, %s\n", err, buf); 17 | exit(1); 18 | } 19 | 20 | int main(int arc, char *argv[]) { 21 | printf("Keymanagement exploration\n"); 22 | OSSL_PROVIDER* def = OSSL_PROVIDER_load(NULL, "default"); 23 | OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new(); 24 | const EVP_KEYMGMT* keymgmt = EVP_KEYMGMT_fetch(libctx, "id-ecPublicKey", NULL); 25 | if (keymgmt == NULL) { 26 | error_and_exit("Could not fetch EVP_KEYMGMT\n"); 27 | } 28 | #if 0 29 | /** 30 | * `evp_keymgmt_get_number` is an internal method. It's not usable by public 31 | * consumers. 32 | */ 33 | printf("Get OSSL_PROVIDER for keymgmt id: %d\n", evp_keymgmt_get_number(keymgmt)); 34 | #endif 35 | const char* name = EVP_KEYMGMT_get0_name(keymgmt); 36 | printf("keymgmt name: %s\n", name); 37 | 38 | const OSSL_PROVIDER* provider = EVP_KEYMGMT_get0_provider(keymgmt); 39 | if (provider == NULL) { 40 | error_and_exit("Could not get OSSL_PROVIDER\n"); 41 | } 42 | printf("provider name: %s\n", OSSL_PROVIDER_get0_name(provider)); 43 | 44 | exit(EXIT_SUCCESS); 45 | } 46 | -------------------------------------------------------------------------------- /notes/aes.md: -------------------------------------------------------------------------------- 1 | ## Advanced Encryption Standard 2 | Symmetric key algorithm where the same key is used for encryption and 3 | decryption. 4 | 5 | ``` 6 | 128 +---------+ 7 | x --->| AES |-----> y 8 | +---------+ 9 | ↑ 10 | | 128/192/256 11 | k 12 | ``` 13 | Notice the block size is always 128-bits (16 bytes) regardless of the keysize. 14 | 15 | The number of rounds depends on the key length 128/192/256: 16 | ``` 17 | Key length | Rounds 18 | -----------|-------- 19 | 128 | 10 20 | 192 | 12 21 | 256 | 14 22 | ``` 23 | 24 | NSA allows AES for classified data up to TOP SECRET with 192 or 256 bit keys. 25 | 26 | As opposed to DES it is not a Fiestel cipher. AES encrypts the whole 128 bits in 27 | each round which is different from what a Fiestel network cipher does. 28 | TODO: include an example of the below in terms of an input message and a 29 | key using ascii characters. 30 | 31 | ``` 32 | 127 0 33 | +---------------------------------+ +-----------------+ 34 | | | | Key k | 35 | +---------------------------------+ +-----------------+ 36 | ↓ ↓ 37 | +---------------------------------+ k₀ +------------------+ 38 | | KeyAddition |←-------| Transform 1 | 39 | +---------------------------------+ +------------------+ 40 | Round 0 ↓ ↓ 41 | +---------------------------------+ | Confusion 42 | | Byte substitution | | 43 | +---------------------------------+ | 44 | ↓ | 45 | +---------------------------------+ | Diffusion 46 | | ShiftRow | | 47 | +---------------------------------+ | 48 | ↓ | 49 | +---------------------------------+ | Diffusion 50 | | MixColumn | | 51 | +---------------------------------+ | 52 | ↓ ↓ 53 | +---------------------------------+ k₁ +------------------+ 54 | | KeyAddition |←-------| Transform 1 | 55 | +---------------------------------+ +------------------+ 56 | ↓ 57 | . 58 | . 59 | . 60 | . 61 | Round 9 ↓ | 62 | +---------------------------------+ | 63 | | Byte substitution | | 64 | +---------------------------------+ | 65 | | 66 | +---------------------------------+ | 67 | | ShiftRow | | 68 | +---------------------------------+ | 69 | ↓ 70 | +---------------------------------+ +-----------------+ Key widening 71 | | KeyAddition |<--------| Transform 9 | 72 | +---------------------------------+ +-----------------+ 73 | 74 | ``` 75 | Notice that each round has four layers (except for the last round which does 76 | not have the MixColumn layer) and for 128-bits we have 10 rounds. 77 | 78 | Remember that confusion is about making the relationship between the key and 79 | the ciphertext as complex and involved as possible. 80 | 81 | Diffusion refers to how each bit in the plaintext influences many of the bits 82 | in the ciphertext. 83 | 84 | AES is byte oriented so all operations are done on bytes and not individual 85 | bits as was done in DES. 86 | 87 | ### Byte Substitution 88 | 89 | ``` 90 | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 16 bytes (16*8=128) 91 | +---------------+ +---------------+ +---------------+ +---------------+ 92 | |B₀ |B₁ |B₂ |B₃ | |B₄ |B₅ |B₆ |B₇ | |B₈ |B₉ |B₁₀|B₁₁| |B₁₂|B₁₃|B₁₄|B₁₅| 93 | +---------------+ +---------------+ +---------------+ +---------------+ 94 | ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 95 | +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ 96 | |S| |S| |S| |S| |S| |S| |S| |S| |S| |S| |S| |S| |S| |S| |S| |S| 97 | +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ --+ +-+ +-+ +-+ +-+ 98 | ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 99 | +---------------+ +---------------+ +---------------+ +---------------+ 100 | |B₀ |B₁ |B₂ |B₃ | |B₄ |B₅ |B₆ |B₇ | |B₈ |B₉ |B₁₀|B₁₁| |B₁₂|B₁₃|B₁₄|B₁₅| 101 | +---------------+ +---------------+ +---------------+ +---------------+ 102 | 103 | ↓ ↓ ↓ ↓ 104 | +-----------+ +-----------+ +-----------+ +-----------+ 105 | | Sub | | Sub | | Sub | | Sub | 106 | +-----------+ +-----------+ +-----------+ +-----------+ 107 | ↓ ↓ ↓ ↓ 108 | +---------------+ +---------------+ +---------------+ +---------------+ 109 | |B₀ |B₁ |B₂ |B₃ | |B₄ |B₅ |B₆ |B₇ | |B₈ |B₉ |B₁₀|B₁₁| |B₁₂|B₁₃|B₁₄|B₁₅| 110 | +---------------+ +---------------+ +---------------+ +---------------+ 111 | 112 | ``` 113 | 114 | ### Substitutions S-boxes 115 | Notice that there are 16 s-boxes and differenct from DES they are all the same. 116 | The input to each s-box is 1 byte (8 bits) and the s-box will 117 | ``` 118 | Ai +---------------+ B'i +---------------+ Bi 119 | ---> |GF(2⁸) inverse | ----> |affine mapping | ----> 120 | +---------------+ +---------------+ 121 | ``` 122 | ``` 123 | S(Ai) = Bi 124 | 125 | A=C2 126 | Which we split in two so that we can look the value up in the lookup table. 127 | So x =12 and y=2 = 1100 0010 <- input to lookup 128 | Bi = S(Ai) = 25₁₆ = 0010 0101 <- output from lookup 129 | ``` 130 | Notice that the values are hex and we have two of them to the lookup table will 131 | have 16x16=256 entries. 132 | 133 | In contrast to DES where the lookup tables were secret (how they were constructed 134 | that is), I think they were generated randomly and the checked if known attacks 135 | were possible, in AES they are not randomly generated and there is a mathematical 136 | structure to it. 137 | 138 | So we have Ai which are the following bits: 139 | ``` 140 | Ai = 1100 0010 141 | ``` 142 | But this can also be viewed as a polynomial: 143 | ``` 144 | A= 1 1 0 0 0 0 1 0 (bits) 145 | 146 | Ai(x) = 1x⁷+1x⁶+0x⁵+0x⁴+0x³+0x²+1x¹+0x⁰ (polynomial) 147 | = x⁷+x⁶+³+1x¹ 148 | = x⁷+x⁶+x 149 | ``` 150 | Now, we have to compute the inverse of this polynomial. 151 | ``` 152 | B'i(x) = x⁵+x³+x²+x+1 = A(x)^-1 153 | 0010 1111 154 | 155 | (x⁷+x⁶+x)(x⁵+x³+x²+x+1) = 1 mod x⁸+x⁴+x³+x+1 156 | ↑ 157 | AES irreducalbe polynomial 158 | ``` 159 | 160 | -------------------------------------------------------------------------------- /notes/asn1.md: -------------------------------------------------------------------------------- 1 | ### Abstract Syntax Notation One (ASN.1) 2 | The goal is to describe the interface between two entities exchanging 3 | information. This enables the files/messages in this format to be used by 4 | different languages. Is used in X.509 (SSL, HTTPS), LDAP, VoIP, SNMP, LTE 5 | (3G, 4G). 6 | 7 | Is similar to ProtoBuf or Thrift which might have been used today but ASN1 8 | has been a standard since 1984, and when the HTTPS spec, in 1994, was created 9 | those protocols were not available. 10 | 11 | ASN1 also contains serialization formats which specify ways to convert in-mem 12 | data structures into a series of bytes. And from a series of bytes into 13 | in-mem data structures. 14 | 15 | #### Serialization formats 16 | Distinguished Encoding Rules (DER) is used which is a variant of Basic Encoding 17 | Rules (BER) but with restrictions that force the serialization to be identical 18 | for certain types. For example a Boolean value in BER could be any of 255 non 19 | zero values would be considered a true value and DER would only allow one 20 | value. This is especially important for crypto where things like digital 21 | signatures. 22 | 23 | The DER encoded data format is often encoded as base64 which is called PEM. 24 | 25 | #### Basic syntax 26 | * Comments start with '--' and end with a matching '--' or end of line. 27 | * Is case senstive. 28 | * Keywords start with capital letters. 29 | * Underscore cannot be used in identifiers or keywords 30 | * Assignments use ::= (similar to what can be used in Make files) 31 | 32 | Strings can be Character strings "bajja", Binary strings '1010'B or 33 | Hexadecimal strings '1a'H. 34 | 35 | 36 | #### INTEGER 37 | Just like normal integers but they can be any size which is great for things 38 | like RSA keys. 39 | 40 | #### Strings 41 | There are many types of strings. These are not null terminated. 42 | 43 | #### OBJECT IDENTIFIERS 44 | Are globally unique sequences of integers and are mostly used to identify 45 | standards, algoritms, certificate extensions, orgs, etc. 46 | For example: 47 | ``` 48 | 2.5 is the "Directory Service" 49 | ``` 50 | There is an online service that can be used to look up what an OID identifies: 51 | http://oid-info.com/get/1.3.6.1.4.1.11129. 52 | 53 | #### SEQUENCE 54 | This is like struct in c. 55 | 56 | #### SEQUENCE OF 57 | This is like an array in c. 58 | 59 | #### OPTIONAL 60 | Fields of a SEQUENCE or a SET can be marked as option in which case they will 61 | be missing from the binary stream. 62 | 63 | #### DEFAULT 64 | Fields of a SEQUENCE or a SET can be marked as DEFAULT and given a value which 65 | will be assigned that value if no value was provided for that field 66 | 67 | #### Encoding 68 | Defines how the values defined in asn1 should be translated into bytes and 69 | from bytes into asn1 (encoding/decoding). 70 | 71 | The format is of Tag/Type, Length, Value. So first in the stream there will be 72 | a type which is called a Tag, followed by the length of the value of that 73 | type/tag, and that is followed by the value itself: 74 | ``` 75 | +--------------------------------------------------------+ 76 | | Type | Length | Value | 77 | +--------------------------------------------------------+ 78 | ``` 79 | For example an INTGER value of 5 could be encoded as: 80 | ``` 81 | Tag Length Value 82 | 02 03 01 00 05 83 | ``` 84 | Notice that the value contains more than just the 5, more on this later. 85 | 86 | The Type/Tag is one byte (one byte): 87 | ``` 88 | 7 5 4 0 89 | +--------------------------------------------------------+ 90 | | Class | Form | Tag | 91 | +--------------------------------------------------------+ 92 | 93 | Class: 94 | 00 = UNIVERSAL 95 | 01 = APPLICATION 96 | 10 = Context-Specific 97 | 11 = Private 98 | 99 | Form: 100 | 0 = Primitive (no subtypes) 101 | 1 = Constructed (contains subtypes) 102 | 103 | Tag: 104 | 1 = BOOLEAN 105 | 2 = INTEGER 106 | 3 = BIT STRING 107 | 4 = OCTET STRING 108 | 5 = NULL 109 | 6 = OBJECT_IDENTIFIER 110 | 9 = REAL 111 | 10 = SEQUENCE (OF) 112 | 16 = IASTRING 113 | 1A = VisibleString 114 | ``` 115 | In OpenSSL these values can be found in include/openssl/asn1.h. 116 | 117 | #### Module 118 | A module is the top level container 119 | ``` 120 | TestModule DEFINITIONS ::= { 121 | Age ::= INTEGER (0..120) DEFAULT 45 122 | Tired ::= BOOLEAN 123 | } 124 | ``` 125 | The types we can use in an asn1 module are BOOLEAN, INTEGER, ENUMERATED, REAL 126 | and NULL (information is missing/absent). 127 | When we have our type set up we can use tools to turn the abstract data into 128 | a bit stream. The bit stream can be of different formats, like Basic Encoding 129 | Rule (BER) for example. 130 | 131 | ### Privacy Enhanced Email (PEM) 132 | Is a base64 (binary-to-text encoding) translation of BER/DER asn1. 133 | 134 | 135 | ### ASN1 in OpenSSL 136 | There is an example in [asn1.c](../asn1.c) which is being used for exploring 137 | asn1 funtionality. There are macros in this file that are used internally in 138 | OpenSSL which are really just used at the moment to see what is generated in 139 | isolation. 140 | 141 | To run asn1.c through the preprocessor the following target can be used: 142 | ```console 143 | $ make asn1_prep 144 | ``` 145 | 146 | This will generate the following code: 147 | ```c 148 | static const ASN1_AUX something_aux = { 149 | ((void *)0), 0, 0, 0, something_cb, 0, ((void *)0) 150 | }; 151 | 152 | static const ASN1_TEMPLATE something_seq_tt[] = { 153 | { (0), (0), __builtin_offsetof ( something , age) , "age", (ASN1_INTEGER_it) } 154 | }; 155 | 156 | const ASN1_ITEM * something_it(void) { 157 | static const ASN1_ITEM local_it = { 158 | 0x1, 16, something_seq_tt, sizeof(something_seq_tt) / sizeof(ASN1_TEMPLATE), &something_aux, sizeof(something), "something" }; 159 | return &local_it; 160 | } 161 | 162 | something *d2i_something(something **a, const unsigned char **in, long len) { 163 | return (something *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, (something_it())); 164 | } 165 | 166 | int i2d_something(const something *a, unsigned char **out) { 167 | return ASN1_item_i2d((const ASN1_VALUE *)a, out, (something_it())); 168 | } 169 | 170 | something *something_new(void) { 171 | return (something *)ASN1_item_new((something_it())); 172 | } 173 | 174 | void something_free(something *a) { 175 | ASN1_item_free((ASN1_VALUE *)a, (something_it())); 176 | } 177 | ``` 178 | Just a note about the naming of the functions generated. something_it creates 179 | a new ASN1_ITEM (it = item). d2i_something converts from DER, which is the 180 | binary format, to internal (i) C structure which in our case is struct something. 181 | 182 | -------------------------------------------------------------------------------- /notes/bignum.md: -------------------------------------------------------------------------------- 1 | ## BIGNUM (BN) 2 | Bit-Integer arithemtic involve numbers that don't fit into single 32/64-bit 3 | registers. Instead the digits need to be stored in memory. These digits are 4 | stored in an array, divided into chunks. 5 | 6 | Is needed for cryptographic functions that require arithmetic on large numbers 7 | without loss of precision. A BN can hold an arbitary sized integer and 8 | implements all operators. 9 | 10 | Usage: 11 | ```c 12 | BIGNUM* three = BN_new(); 13 | BN_set_word(three, 3); 14 | BN_free(three); 15 | ``` 16 | 17 | `crypto/bn/bn_local.h` 18 | ```c 19 | struct bignum_st { 20 | BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit 21 | * chunks. */ 22 | int top; /* Index of last used d +1. */ 23 | /* The next are internal book keeping for bn_expand. */ 24 | int dmax; /* Size of the d array. */ 25 | int neg; /* one if the number is negative */ 26 | int flags; 27 | }; 28 | ``` 29 | 30 | 64 bit-processors: 31 | ```c 32 | # define BN_ULONG unsigned long 33 | # define BN_BYTES 8 34 | ``` 35 | 36 | 32 bit-processors: 37 | ```c 38 | # define BN_ULONG unsigned int 39 | # define BN_BYTES 4 40 | ``` 41 | 42 | So `d`, the digits will be a pointer to an unsigned long or int depending on the 43 | processor used, and it will be divided into chunks the size of BN_BITS2: 44 | ```c 45 | # define BN_BITS2 (BN_BYTES * 8) 46 | # define BN_BITS (BN_BITS2 * 2) 47 | ``` 48 | So for a 64-bit processor we would have something like: 49 | ``` 50 | 8 8 8 8 8 8 51 | +----------------------------------------------------+ 52 | | | | | | | | 53 | +----------------------------------------------------+ 54 | ↑ ↑ 55 | d dmax 56 | ``` 57 | A newly initialized BIGNUM would have the following values: 58 | ```console 59 | (BIGNUM) $0 = { 60 | d = 0x0000000000000000 61 | top = 0 62 | dmax = 0 63 | neg = 0 64 | flags = 1 65 | } 66 | ``` 67 | If we try setting word as shown above the digits array must first be set or 68 | expanded. Depending on the value being being set will determine the max number 69 | of elements in the digits array (dmax). In the case of `3` this would only 70 | need one chunk/slot. The slot(s) are then populated in BN_set_word 71 | ```console 72 | (lldb) expr a->d[0] 73 | (unsigned long) $7 = 3 74 | 75 | (lldb) expr *a 76 | (BIGNUM) $9 = { 77 | d = 0x00000000004056d0 78 | top = 1 79 | dmax = 1 80 | neg = 0 81 | flags = 1 82 | } 83 | ``` 84 | Now, lets take a look at a more complicated bitnum. 85 | ```console 86 | (lldb) expr *pub_key 87 | (BIGNUM) $15 = { 88 | d = 0x0000000005b15580 89 | top = 24 90 | dmax = 24 91 | neg = 0 92 | flags = 1 93 | } 94 | ``` 95 | So we can see that the array will have 24 chunks of data in it. And remember 96 | that d is just a pointer to the first entry. 97 | 98 | I was wondering how a comparison is done with BIGNUMs 99 | -------------------------------------------------------------------------------- /notes/dh.md: -------------------------------------------------------------------------------- 1 | ### Diffie Hellman Key Exchange 2 | 3 | ``` 4 | Alice Public Bob 5 | a (number < n) g (generator, small prime) b (number < n) 6 | n (big prime number) 7 | 8 | A = g^a mod n B = g^b mod n 9 | A 10 | -----------------> 11 | B 12 | <----------------- 13 | 14 | K_ab = (B)^a mod n K_ab = (A)^b mod n 15 | 16 | 17 | This is same as: This is the same as: 18 | (g^b)^a mod n = g^ab mod p (g^a)^b mod n = g^ab mod p 19 | ``` 20 | Notice that they are both calculating the same value which is the secret key 21 | that will be used for encryption. They have been able to communicate this in the 22 | open and even if Eve gets a₁ or b₁ she does not have a or b, and to brute force 23 | this would take a lot of time. 24 | 25 | ``` 26 | y 27 | y = AES(x) ---------------------> AES⁻¹(y) = x 28 | K_ab K_ab 29 | 30 | ``` 31 | 32 | Example: 33 | ``` 34 | a = 3 g = 5 b = 2 35 | n = 7 36 | 37 | a₁ = 5³ mod 7 = 125 mod 7 = 6 38 | b₁ = 5² mod 7 = 25 mod 7 = 4 39 | 40 | (b₁)³ = 4³ = 64 mod 7 = 1 (secret key) (a₁)² = 6² = 36 mod n = 1 41 | ``` 42 | Notice that `g` for generator is like the starting point on the circle and n is 43 | the max size of the circle after which is will wrap over. 44 | 45 | ``` 46 | n 47 | ______ 48 | / \ 49 | | | <-- g 50 | \______/ 51 | 52 | ``` 53 | Visualize this as a circle (like a clock and 12 is the number n). So we take 54 | our private key (a) and raise g to that, and then mod it to the circle, so this 55 | will be a point some where on the circle. 56 | 57 | ``` 58 | a = 3 59 | a₁ = 5³ mod 7 = 125 mod 7 = 6 60 | 61 | n 62 | ↓ 63 | 7 1 64 | a₁--> 6 _____ 65 | / \ 2 66 | g --> 5 | | 67 | \______/ 3 68 | 4 69 | ``` 70 | Bob does the same and his value will also be somewhere on the circle. 71 | ``` 72 | b = 3 73 | b₁ = 5² mod 7 = 25 mod 7 = 4 74 | 75 | n 76 | ↓ 77 | 7 1 78 | 6 _____ 79 | / \ 2 80 | g --> 5 | | 81 | \______/ 3 82 | 4 83 | ↑ 84 | b₁ 85 | ``` 86 | 87 | They can now share a₁ and b₁ publicly as just knowing the point on the cicle is 88 | not enough, only alice knows how many times around the circle (a times) to get 89 | to the point. 90 | 91 | So after the exchange here is a secret key that both parties can use to encrypt 92 | and decrypt messages and they would use a symmetric cipher like AES for this. 93 | 94 | ### MODP groups 95 | These are predefined prime numbers based on digits of PI, and generator number. 96 | So these are the values of `n` and `g`. 97 | 98 | Remember that both parties must use the same prime (which they use mod p) and 99 | the generator number, and these are simply precomputed values that both can use. 100 | They can specify that these should be used. 101 | 102 | As an example in Node.js a group name can be specified which will then be 103 | used to looked up : 104 | ```c++ 105 | const node::Utf8Value group_name(env->isolate(), args[0]); 106 | const modp_group* group = FindDiffieHellmanGroup(*group_name); 107 | initialized = diffieHellman->Init(group->prime, 108 | group->prime_size, 109 | group->gen); 110 | ``` 111 | 112 | src/crypto/crypto_groups.h: 113 | ```c++ 114 | typedef struct { 115 | const char* name; 116 | const char* prime; 117 | unsigned int prime_size; 118 | unsigned int gen; 119 | } modp_group; 120 | 121 | static const modp_group modp_groups[] = { 122 | #define V(var) reinterpret_cast(var) 123 | { "modp1", V(group_modp1), sizeof(group_modp1), two_generator }, 124 | { "modp2", V(group_modp2), sizeof(group_modp2), two_generator }, 125 | { "modp5", V(group_modp5), sizeof(group_modp5), two_generator }, 126 | { "modp14", V(group_modp14), sizeof(group_modp14), two_generator }, 127 | { "modp15", V(group_modp15), sizeof(group_modp15), two_generator }, 128 | { "modp16", V(group_modp16), sizeof(group_modp16), two_generator }, 129 | { "modp17", V(group_modp17), sizeof(group_modp17), two_generator }, 130 | { "modp18", V(group_modp18), sizeof(group_modp18), two_generator } 131 | #undef V 132 | }; 133 | 134 | static const unsigned char group_modp5[] = { 135 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 136 | 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 137 | 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 138 | 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 139 | 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, 0xef, 0x95, 140 | 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 141 | 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 142 | 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 143 | 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 144 | 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, 0xee, 0x38, 0x6b, 0xfb, 145 | 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 146 | 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 147 | 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 148 | 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 149 | 0xfd, 0x24, 0xcf, 0x5f, 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 150 | 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb, 151 | 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 152 | 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, 153 | 0xca, 0x23, 0x73, 0x27, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 154 | 0xff, 0xff }; 155 | ``` 156 | The FindDiffieHellmanGroup function simply iterates over all the names 157 | and compares them to the passed in group name. Would it not be better to use a 158 | map for this? TODO: take a closer look at this code. 159 | 160 | Notice that the struct mod_p_group has a prime which is the character array 161 | we see above which is the value of the prime to use (is part of the spec), and 162 | it also as the size of the prime, and a generator value of 2. 163 | ```console 164 | (lldb) expr group->prime_size 165 | (const unsigned int) $16 = 192 166 | ``` 167 | 168 | modp1, modp2 169 | 170 | modp5, modp15, modp16, modp17, modp18 171 | 172 | 173 | ### Safe prime 174 | For a prime to be safe then for prime `p`, (p-1/2) must also be prime. 175 | ``` 176 | p = 11 177 | (11-1)/2 = 5 178 | ``` 179 | So 11 would be a safe prime. 180 | 181 | ### OpenSSL implementation 182 | We can find the Diffie-Hellman struct in `crypto/dh/dh_local.h`. 183 | ```c 184 | struct dh_st { 185 | ... 186 | BIGNUM *pub_key; /* g^x % p */ 187 | BIGNUM *priv_key; /* x */ 188 | ... 189 | } 190 | ``` 191 | `openssl/crypto/dh/dh_key.c` 192 | 193 | -------------------------------------------------------------------------------- /notes/ec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danbev/learning-openssl/2e288d1b318e6ae29d39facbb783bb9606fdadba/notes/ec.png -------------------------------------------------------------------------------- /notes/elgamal.md: -------------------------------------------------------------------------------- 1 | ## Elgamal encryption scheme 2 | Diffie-Hellman uses the descrete logarithm problem (DLP) to establish a key 3 | exchange. This section looks at an encryption scheme that used DLP. 4 | 5 | For some background here we are talking about public-key algorithms and they 6 | can be used for multiple things: 7 | ``` 8 | Descrete Logarithm 9 | Integer factorization | Zp^* EC 10 | ----------------------------------------------------------------------- 11 | Key exchange | RSA | DH | ECDH 12 | Digital signatures | RSA | Elgamal+DSA | ECDSA 13 | Encryption | RSA | Elgamal | EC-Elgamal 14 | ``` 15 | 16 | 17 | First lets recall the Diffie-Hellman key exchange using Zp^*: 18 | ``` 19 | Alice Public domain parameters Bob 20 | ------------------------------------------------------------------------ 21 | α (generator/primitive element) 22 | p (prime number) 23 | 24 | a = KprA ∈ {2,..., p-2} b = KprB ∈ {2,..., p-2} 25 | A = KpubA = α^a mod p <-----------------------> B = KpubB = α^b mod p 26 | 27 | 28 | K_ab = (B)^a mod p K_ab = (A)^b mod p 29 | ``` 30 | Now the session keys calculated could be used as the key for a symmetric 31 | encryption algorithm. But in the case of Elgamal we want to use this to encrypt 32 | directly. This is done by multiplying the message with the secret key: 33 | ``` 34 | message * K_ab mod p = y --------------------------> y * K_ab^-1 mod p 35 | y / K_ab mod p 36 | ``` 37 | This is basically what Elgamal does, but it changes some of the earlier parts 38 | of the scheme for efficiency reasons (I think). 39 | 40 | So Elgamal is a variant of DH is not very difficult to understand it is pretty 41 | much as explained above but in pratice the implementation differs from this 42 | simplistic view. It reorders steps in DH. 43 | 44 | Elgamal was invented around 1985 and Taher Elgamal was the inventor. 45 | 46 | 47 | ``` 48 | Alice Bob 49 | ------------------------------------------------------------------------ 50 | α (generator/primitive element) 51 | p (prime number) 52 | 53 | (β, p, α) Kpr = d ∈ {2,..., p-2} 54 | <--------------------------- Kpub = β = α^d mod p 55 | i ∈ {2,..., p-2} 56 | K_e = α^i mod p ("Ephemeral"/"temporary or short lived" key) 57 | (same as Alices public key in normal DH) 58 | 59 | K_m = β^i mod p ("Masking" key) 60 | (same as the session key in normal DH) 61 | 62 | y = x * K_m mod p (x = message) 63 | (y, K_e) 64 | ------------------------------> 65 | K_m = K_e^d mod p 66 | x = y K_m^-1 mod p 67 | x = y / K_m mod p 68 | 69 | ``` 70 | 71 | Recall: 72 | ``` 73 | α^x = A mod p 74 | 75 | x = Kpr (private key) 76 | A = Kpub (public key) 77 | α = generator/primitive element 78 | ``` 79 | 80 | Notice that Bob now has the domain parameters which he choses and they are not 81 | in the public domain like in DH. 82 | 83 | ``` 84 | y * K_m^-1 = y * (K_e^d)^-1 mod p 85 | y * K_m^-1 = (x*K_m) * K_e^-d mod p 86 | y * K_m^-1 = x*β^i * (α^i)^-d) mod p 87 | y * K_m^-1 = x(α^d)^i * (α^i)^-d) mod p 88 | y * K_m^-1 = xα^id * α^-id mod p 89 | y * K_m^-1 = xα^(id-id) mod p 90 | y * K_m^-1 = xα^(0) mod p 91 | y * K_m^-1 = x * 1 mod p 92 | ``` 93 | 94 | Now if you are only going to encrypt once then there are the same number of 95 | steps in both DH and Elgamal. But if Bob wants to communicate with multiple 96 | people and encrypt then the same public key is used. 97 | The public key K_e must be different for every plaintext that is to be 98 | encrypted. So we have to use the generator to get a new value for `i` each 99 | time we want to encrypt otherwise if we reuse the same value that will result 100 | in the same ciphertext. The masking key need to change otherwise we are just 101 | multiplying the same values to produce y. 102 | -------------------------------------------------------------------------------- /notes/err.md: -------------------------------------------------------------------------------- 1 | ### Errors in OpenSSL 2 | 3 | Each thread has a thread local struct which look like this: 4 | ```c 5 | #define ERR_NUM_ERRORS 16 6 | 7 | struct err_state_st { 8 | int err_flags[ERR_NUM_ERRORS]; 9 | unsigned long err_buffer[ERR_NUM_ERRORS]; 10 | char *err_data[ERR_NUM_ERRORS]; 11 | size_t err_data_size[ERR_NUM_ERRORS]; 12 | int err_data_flags[ERR_NUM_ERRORS]; 13 | const char *err_file[ERR_NUM_ERRORS]; 14 | int err_line[ERR_NUM_ERRORS]; 15 | const char *err_func[ERR_NUM_ERRORS]; 16 | int top, bottom; 17 | }; 18 | # endif 19 | ``` 20 | So there can be a maximum of 16 errors. And each error can have flags. 21 | 22 | ```c 23 | ERR_STATE *es; 24 | int top; 25 | 26 | es = err_get_state_int(); 27 | ``` 28 | `err_get_state_int` will get the thread local struct or create a new one 29 | if one does not already exist. 30 | 31 | ### Raising/Setting an error 32 | This is done using one of the `ERR_raise` macros: 33 | ```c 34 | # define ERR_raise(lib, reason) ERR_raise_data((lib),(reason),NULL) 35 | # define ERR_raise_data \ 36 | (ERR_new(), \ 37 | ERR_set_debug(OPENSSL_FILE,OPENSSL_LINE,OPENSSL_FUNC), \ 38 | ERR_set_error) 39 | ``` 40 | And this would be used like this: 41 | ```c 42 | ERR_raise_data(example_lib, reason_1, "after setting mark"); 43 | ``` 44 | Which would get expanded by the preprocessor as: 45 | ```console 46 | $ make err_pre 47 | ``` 48 | ```c 49 | (ERR_new(), ERR_set_debug("err.c",45,__func__), ERR_set_error)(example_lib, reason_1, "after setting mark"); 50 | ``` 51 | ERR_new will find an entry at the top of the error queue and clear that entry. 52 | ERR_set_debug will then add to that entry, as will ERR_set_error. This syntax 53 | migth look odd if you have not seen it before but is 54 | [legal](https://github.com/danbev/learning-c/blob/master/comma.c) and just think 55 | of it as: 56 | ```c 57 | ERR_new(); 58 | ERR_set_debug("err.c",45,__func__); 59 | ERR_set_error(example_lib, reason_1, "after setting mark"); 60 | ``` 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /notes/hash.md: -------------------------------------------------------------------------------- 1 | ### Hashing 2 | Most hashing functions take a variable input and produce a fixed length output. 3 | ``` 4 | +-----------------------------------+ 5 | | Message M | (any length) 6 | +-----------------------------------+ 7 | | 8 | ↓ 9 | +-----------------------------------+ 10 | \ / 11 | \ Hash function H(M) / 12 | \ / 13 | ------------------------------- 14 | | 15 | ↓ 16 | +-----------------+ 17 | | Hash value | (fixed length) 18 | +-----------------+ 19 | ``` 20 | 21 | One usage of hashing is where we want to create a digital signature of a 22 | message or a file (something larger than the size than our signature algorighm 23 | key) it would have to be split into blocks and encrypted separately. If this 24 | is a large file that would take some time, and the same thing would have to be 25 | done on the receiving side. What can be done instead is pass the message/file 26 | through the hash function and get back a fixed length output, which we can then 27 | sign using our signature algorighm. The signature is also sent with the message 28 | and if we did not sign just the hash but the entire message we would double the 29 | size of the data to be sent, perhaps over a network. 30 | 31 | 32 | ### RSA digital signature 33 | ``` 34 | 35 | Alice Bob 36 | <---- Kpub ----- Z = h(x) 37 | <---- (x, s) ---- s = sig_kpr(Z) 38 | 39 | Z = h(x) 40 | sig_kpub(Z) = true/false 41 | ``` 42 | 43 | ### SHA-1 44 | 45 | ``` 46 | +-----------------------------------+ 47 | | Message M | (any length) 48 | +-----------------------------------+ 49 | | 50 | ↓ 51 | +-----------------------------------+ 52 | \ / 53 | \ SHA-1(M) / 54 | \ / 55 | ------------------------------- 56 | | 57 | ↓ 58 | +-----------------+ 59 | | Hash value | 160 bits 60 | +-----------------+ 61 | ``` 62 | SHA-1 uses a Merkle-Damngård construction: 63 | ``` 64 | x = (x₁....xn) 65 | ↓ 66 | +--------------+ 67 | | padding | Output size if 512 bits 68 | +--------------+ 69 | ↓ ↓-----------+ 70 | +--------------+ | 71 | \ compression / | This value is fed back into the compression function 72 | +-----------+ | with the xi. The size of this value is 160 bits 73 | ↓ | 74 | +----------------+ 75 | | When xn inputs have been processed we continue 76 | ↓ 77 | H(x) the hash function. x is 160 bits 78 | 79 | ``` 80 | the padding and compression is the Merkle-Damgard construction. 81 | 82 | Lets take a closer look at the compression function: 83 | Compression: 84 | ``` 85 | x_i (512 bits) H_i-1 (160 bits) 86 | | | 87 | ↓ ↓----------+ 88 | +----------------+ W₀ +----------+ | 89 | | Msg scheduler | ------> | Round 0 | | 90 | +----------------+ 32 bit +----------+ | 80 rounds 91 | | ↓ | 92 | | W₁ +----------+ | 93 | +----------------> | Round 1 | ↓ 94 | | 32 bit +----------+ | 95 | ... ... | 96 | | ↓ | 97 | | W₈₀ +----------+ | 98 | +----------------> | Round 79 | | 99 | 32 bit +----------+ | 100 | | 32 | 101 | [+]<--------+ add modulo 2³² 102 | | 32 103 | ↓ 104 | ``` 105 | `w` are sub messages of size 106 | 107 | H_i-1 which is 160 bits is divided into four groups of 40 bits each 108 | ``` 109 | +------------------------------------+ 110 | | 160 | 111 | +------------------------------------+ 112 | ↓ ↓ ↓ ↓ ↓ 113 | +----+ +----+ +----+ +----+ +----+ 114 | | A | | B | | C | | D | | E | 115 | +----+ +----+ +----+ +----+ +----+ 116 | 32 32 32 32 32 117 | 118 | ``` 119 | These 32 bit (words) are called the state. Notice that for the first round there 120 | nothing, that is H₀ so the initial state is provided as: 121 | ``` 122 | S[0] = 0x67452301; 123 | S[1] = 0xefcdab89; 124 | S[2] = 0x98badcfe; 125 | S[3] = 0x10325476; 126 | S[4] = 0xc3d2e1f0; 127 | ``` 128 | 129 | Rounds: 130 | 4x20 = 80 rounds 131 | There are 4 stages: 132 | ``` 133 | stage t=1, round j=0...19 134 | stage t=2, round j=20...39 135 | stage t=3, round j=40...59 136 | stage t=4, round j=60...79 137 | ``` 138 | 139 | Each round has 5x32 (160) bits inputs (A, B, C, D, E) plus the message 140 | schedule word W_j, which is also 32 bits. 141 | ``` 142 | A B C D E 143 | (32) (32) (32) (32) (32) 144 | ↓ ↓ ↓ ↓ ↓ 145 | +--------------------------+ 146 | w_j -> | Round j | 147 | (32) +--------------------------+ 148 | 149 | 150 | +--------------------------+ 151 | | A | B | C | D | E | 152 | +--------------------------+ 153 | | | | | | 154 | | ↓ ↓ ↓ | 155 | | +-----------+ ↓ 156 | | | f(B, C, D)|->[+] 157 | +-----+ +-----------+ ↓ 158 | |<<< 5|--------------->[+] 159 | +-----+ | | | ↓ 160 | | | | | [+]<---- Wj message scheduler value (32 bits) 161 | | +-----+ | | | 162 | | |<<<30| | | | 163 | | +-----+ | | | 164 | | | | | | 165 | | +-+ | | | 166 | | | | | | 167 | +-----+ | | | ↓ 168 | | | | | [+]<---- kt round constant 169 | +-----|--------------+ 170 | | | | | | 171 | | | | | +----+ 172 | | | | +----+ | 173 | | | +--+ | | 174 | ↓ ↓ ↓ ↓ ↓ 175 | +--------------------------+ 176 | | A | B | C | D | E | 177 | +--------------------------+ 178 | 179 | 180 | ``` 181 | The 4 round functions are: 182 | ``` 183 | f0(B, C, D) = (B & C) | (!B & D) 184 | f1(B, C, D) = B ^ C ^ D 185 | f2(B, C, D) = (B & C) | (B & D) | (C & D) 186 | f3(B, C, D) = B ^ C ^ D 187 | ``` 188 | And the 4 round constats are: 189 | ``` 190 | c0 = 5A827999 191 | c1 = 6ED9EBA1 192 | c2 = 8F1BBCDC 193 | c3 = CA62C1D6 194 | ``` 195 | And finally we have the message scheduler values: 196 | ``` 197 | ``` 198 | 199 | 200 | This can be compared to block ciphers and how they work: 201 | ``` 202 | K m 203 | +----------------+ k₀ +----------+ 204 | | Key scheduler | ------> | Round 0 | 205 | +----------------+ +----------+ 206 | | ↓ 207 | | k₁ +----------+ 208 | +----------------> | Round 1 | 209 | | +----------+ 210 | ... ... 211 | | ↓ 212 | | ks-1 +----------+ 213 | +----------------> | Round s-1| 214 | +----------+ 215 | 216 | ``` 217 | 218 | ### SHA-3 219 | November 2007 NIST issues a call for algorithms. 220 | October 2008 deadline and they recieved 64 submissions. 221 | December 2010 5 algorithms were left in the competition. 222 | October 2012 Keccak was selected as SHA-3. 223 | 224 | ``` 225 | +-----------------------------------+ 226 | | Message M | (any lenght) 227 | +-----------------------------------+ 228 | | 229 | ↓ 230 | +-----------------------------------+ 231 | \ / 232 | \ SHA-3 Hash function H(M) / 233 | \ / 234 | ------------------------------- 235 | | 236 | ↓ 237 | +-----------------+ 238 | | Hash value | fixed lengts: 239 | +-----------------+ 224/256/384/512 240 | ``` 241 | Notice the fixed lengths (4) of them. 242 | ``` 243 | 224 2¹¹² 3DES key length 244 | 256 2¹²⁸ AES key length 245 | 384 2¹⁹² AES key length 246 | 512 2²⁵⁶ AES key length 247 | ``` 248 | Recall that 2¹¹² are the steps an attacker needs to produce to create a 249 | collision. 250 | 251 | #### Kerrak 252 | Can be used for other things and not just sha3. 253 | 254 | Sponge construction: 255 | 1. Absorbing phase, input (like when you release a sponge it will such up fluid) 256 | x₁ is read and processed. 257 | 2. Squeezing phase, ouput (like when you squeeze the spong fluid will go out) 258 | 259 | Parameters: 260 | state which is like the internal bus length of Kerrac which can be configured 261 | with a length (l) of `b = 25 * 2&l, where l={0,1,2,3,4,5,6}` which gives 262 | `b ∈ { 25, 50, 100, 200, 400, 800, 1600 }`. 263 | For SHA3 `l` must be 6 so b will be 1600. 264 | 265 | rounds: n_r = 12 + 2l, which for SHA-3 becomes n_r = 12 + 2*6 = 24 266 | 267 | output lengths: 268 | ``` 269 | output length bus width block size (r) capacity (c) 270 | 224 1600 1152 1600-1152=448 271 | 256 1600 1080 1600-1080=512 272 | 384 1600 832 1600-832=768 273 | 512 1600 576 1600-576=1024 274 | 224 275 | 276 | -------------------------------------------------------------------------------- /notes/hmac.md: -------------------------------------------------------------------------------- 1 | ## Hash Message Authentication Code (HMAC) 2 | What these are intended to do is to protect/guard agains ciphertext 3 | manipulation. So just think about a message that gets encrypted into cipertext, 4 | the only person that can decrypt is someone in possession of the private key 5 | (assuming symmatric key encryption). But is it possible for someone to modify 6 | the ciphertext. When the encryption algrorithm uses a block cipher this change 7 | would affect the whole block but with a stream cipher it would only affect a 8 | single byte. Anyway, this is what a HMAC is designed to protect, the receiver 9 | can recalculate the tag generated before/after encryption to verify that the 10 | plain-text/cipher-text has not been tampered with. 11 | 12 | ``` 13 | +---------------------+------------------+ 14 | | message | hash(message) | 15 | +---------------------+------------------+ 16 | 17 | hash(message) = fixed length bits unique to the input message. And one way. 18 | ``` 19 | So in this case the receiver can verify the message was not tampered with. But 20 | someone intercepting this message could update the message and then re-run the 21 | hash function with that modified message and still the receiver would not know 22 | that it had been tampered with. 23 | 24 | We need to mix some encryption into this, like so: 25 | ``` 26 | +---------------------+------------------+ 27 | | message | hash(k | message)| 28 | +---------------------+------------------+ 29 | 30 | k = symmetric key shared is appended to the message before hashing. 31 | hash(message) = fixed length bits unique to the input message. And one way. 32 | ``` 33 | With this solution an attacker can intercept the message and change it, but 34 | without the private key it will not be able to recompute the hash (remember that 35 | the message the attacher intercepts is a hash of the key appended to the message 36 | and they only see the output of the hash function which is a fixed lentgh string 37 | of bits. But there are ways to workaround this depending on the hash function 38 | used, like SHA1 or SHA256. 39 | 40 | ``` 41 | key -> key₁ 42 | -> key₂ 43 | 44 | hash₁ = hash(k₁ | message) 45 | hash₂ = hash(k₂ | hash₁) 46 | or 47 | hash = hash(k₂ | (hash(k₁ | message))) 48 | 49 | +---------------------+--------------------------------+ 50 | | message | hash(k₂ | (hash(k₁ | message)))| 51 | +---------------------+--------------------------------+ 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /notes/issues/node-openssl-build.md: -------------------------------------------------------------------------------- 1 | ### buildtype error 2 | This error has happend now and again, I think mostly after rebasing 3 | the working branch I've got for statically linking 4 | [OpenSSL 3.0](https://github.com/danbev/node/tree/openssl-3.0-statically-linked): 5 | ```console 6 | + exec ./configure --openssl-is-fips 7 | Traceback (most recent call last): 8 | File "/home/danielbevenius/work/nodejs/openssl/tools/gyp_node.py", line 55, in 9 | run_gyp(sys.argv[1:]) 10 | File "/home/danielbevenius/work/nodejs/openssl/tools/gyp_node.py", line 48, in run_gyp 11 | rc = gyp.main(args) 12 | File "/home/danielbevenius/work/nodejs/openssl/tools/gyp/pylib/gyp/__init__.py", line 658, in main 13 | return gyp_main(args) 14 | File "/home/danielbevenius/work/nodejs/openssl/tools/gyp/pylib/gyp/__init__.py", line 625, in gyp_main 15 | [generator, flat_list, targets, data] = Load( 16 | File "/home/danielbevenius/work/nodejs/openssl/tools/gyp/pylib/gyp/__init__.py", line 108, in Load 17 | default_variables['buildtype'])) 18 | KeyError: 'buildtype' 19 | make: *** [Makefile:150: out/Makefile] Error 1 20 | ``` 21 | I added the key `buildtype` when adding for absolue paths in gyp and this was 22 | passed in via the configuration.py file: 23 | ```python 24 | gyp_args = ['--no-parallel', '-Dconfiguring_node=1', 25 | '-Dbuildtype=' + output['target_defaults']['default_configuration']]; 26 | ``` 27 | But this option is only pased when running configuration.py and not when the 28 | Makefile target `out/Makefile`'s recipe runs tools/gyp_node.py. Removing this 29 | and instead using `CONFIGURATION_NAME` should work: 30 | ```python 31 | default_variables.setdefault("PRODUCT_DIR_ABS", os.path.join(output_dir, 32 | default_variables['CONFIGURATION_NAME'])) 33 | ``` 34 | We can check this by touching config.gypi and then running: 35 | ```console 36 | $ make -j8 37 | ``` 38 | 39 | When looking into this issue I noticed that tools/gyp_node.py used 40 | config_fips.gypi which could be deleted now I think. 41 | -------------------------------------------------------------------------------- /notes/issues/node-openssl-cli.md: -------------------------------------------------------------------------------- 1 | ### openssl-cli segment fault issue 2 | After rebasing node the following error occurs when running the `fipsinstall` 3 | command: 4 | ```console 5 | INSTALL PASSED 6 | /bin/sh: line 1: 959689 Segmentation fault (core dumped) "/home/danielbevenius/work/nodejs/openssl/out/Release/openssl-cli" fipsinstall -provider_name libopenssl-fipsmodule -module "/home/danielbevenius/work/nodejs/openssl/out/Release/obj.target/deps/openssl/libopenssl-fipsmodule.so" -out "/home/danielbevenius/work/nodejs/openssl/out/Release/obj.target/deps/openssl/fipsmodule.cnf" 7 | make[1]: *** [node.target.mk:39: /home/danielbevenius/work/nodejs/openssl/out/Release/obj.target/deps/openssl/fipsmodule.cnf] Error 139 8 | make[1]: *** Waiting for unfinished jobs.... 9 | /bin/sh: line 1: 959686 Segmentation fault (core dumped) "/home/danielbevenius/work/nodejs/openssl/out/Release/node_mksnapshot" "/home/danielbevenius/work/nodejs/openssl/out/Release/obj/gen/node_snapshot.cc" 10 | make[1]: *** [node.target.mk:26: /home/danielbevenius/work/nodejs/openssl/out/Release/obj/gen/node_snapshot.cc] Error 139 11 | rm 2bd3ca31970f82ed30158c22940143b927724ad7.intermediate 12 | make: *** [Makefile:110: node] Error 2 13 | ``` 14 | Simply running `make -j8` again will allow this issue to be worked around. 15 | TODO: investigate the cause of this. 16 | -------------------------------------------------------------------------------- /notes/issues/p2align-aix-issue.md: -------------------------------------------------------------------------------- 1 | ## p2align aix64 issue 2 | This issue was discovered when trying to build (statically) OpenSSL 3.0 with 3 | Node.js. 4 | 5 | ### Compile error: 6 | ```console 7 | 05:39:05 Assembler: 8 | 05:39:05 ../deps/openssl/config/archs/aix64-gcc/asm_avx2/crypto/bn/ppc64-mont-fixed.s: line 4: Error In Syntax 9 | 05:39:05 gmake[2]: *** [deps/openssl/openssl.target.mk:1132: /home/iojs/build/workspace/node-test-commit-aix/nodes/aix72-ppc64/out/Release/obj.target/openssl/deps/openssl/config/archs/aix64-gcc/asm_avx2/crypto/bn/ppc64-mont-fixed.o] Error 1 10 | 05:39:05 gmake[2]: *** Waiting for unfinished jobs.... 11 | 05:39:05 gmake[1]: *** [Makefile:105: node] Error 2 12 | 05:39:05 gmake: *** [Makefile:532: build-ci] Error 2 13 | 05:39:05 Build step 'Execute shell' marked build as failure 14 | 05:39:05 Performing Post build task... 15 | ``` 16 | 17 | This contents of the line and file it is referring to looks like this: 18 | ```assembly 19 | .machine "any" 20 | .csect .text[PR],7 21 | .align 5 22 | .p2align 5,,31 23 | ``` 24 | 25 | This assembly source code file is generated as part of the upgrade process 26 | in Node.js. 27 | ```console 28 | $ cd deps/openssl/config 29 | $ make aix64-gcc 30 | ``` 31 | Running this command will configure OpenSSL for `aix64-gcc` and generate the 32 | sources in: 33 | ```console 34 | $ ls -l archs/aix64-gcc/asm_avx2/crypto/bn/ 35 | total 52 36 | -rw-rw-r--. 1 danielbevenius danielbevenius 17861 Jun 1 12:08 bn-ppc.s 37 | -rw-rw-r--. 1 danielbevenius danielbevenius 5189 Jun 1 12:08 ppc64-mont-fixed.s 38 | -rw-rw-r--. 1 danielbevenius danielbevenius 23476 Jun 1 12:08 ppc-mont.s 39 | ``` 40 | `ppc64-mont-fixed.s` is generated by the OpenSSL perl script 41 | `crypto/bn/asm/ppc64-mont-fixed.pl`: 42 | ```console 43 | $ git log --summary crypto/bn/asm/ppc64-mont-fixed.pl 44 | commit 0d40ca47bd86e74a95c3a2f5fb6c67cdbee93c79 45 | Author: Martin Schwenke 46 | Date: Wed Apr 14 14:31:58 2021 +1000 47 | 48 | bn: Add fixed length (n=6), unrolled PPC Montgomery Multiplication 49 | 50 | Overall improvement for p384 of ~18% on Power 9, compared to existing 51 | Power assembling code. See comment in code for more details. 52 | 53 | Multiple unrolled versions could be generated for values other than 54 | 6. However, for TLS 1.3 the only other ECC algorithms that might use 55 | Montgomery Multiplication are p256 and p521, but these have custom 56 | algorithms that don't use Montgomery Multiplication. Non-ECC 57 | algorithms are likely to use larger key lengths that won't fit into 58 | the n <= 10 length limitation of this code. 59 | 60 | Signed-off-by: Amitay Isaacs 61 | Signed-off-by: Alastair D'Silva 62 | Signed-off-by: Martin Schwenke 63 | 64 | Reviewed-by: Tomas Mraz 65 | Reviewed-by: Paul Dale 66 | (Merged from https://github.com/openssl/openssl/pull/15175) 67 | 68 | create mode 100755 crypto/bn/asm/ppc64-mont-fixed.pl 69 | ``` 70 | Notice that this file is quite recent and this might mean that this issue is 71 | not something that we run into before. 72 | 73 | On the system in question the GNU Assembler (GAS) is not used, instead the 74 | assembler is 75 | 76 | ```assembly 77 | $ cat test.s 78 | .machine "any" 79 | .csect .text[PR],7 ;; csect=Control Section, PR=Program Code, 7=alignment(2⁷=128) 80 | .align 5 81 | .p2align 5,,31 82 | 83 | .globl .bn_mul_mont_fixed_n6 84 | .bn_mul_mont_fixed_n6: 85 | mr 9,3 86 | 87 | mtvsrd 32,14 88 | mtvsrd 33,15 89 | mtvsrd 34,20 90 | ``` 91 | ```console 92 | as -v test.s 93 | as V7.2 94 | Assembler: 95 | test.s: line 4: Error In Syntax 96 | ``` 97 | Notice that this Assembler is not amoung the ones assembler versions mentioned 98 | to be [supported](https://github.com/openssl/openssl/blob/master/INSTALL.md#notes-on-assembler-modules-compilation). 99 | 100 | Is it important for us Red Hat/IBM to be able to build using the default 101 | Assembler of could we make GAS a prerequisite perhaps? 102 | After asking around at work apparently there have been issues with GAS on aix 103 | and this is the reason for preferring AIX Assembler (as). It is about installing 104 | GAS and get on with it which I thought. The current idea we have at the moment 105 | is to either add a configuration flag to OpenSSL Configure or perhaps add a 106 | new arch like aix64-gcc-as which would hopefully enable us to add a check in 107 | the perl script which generates the source file. We also need to make sure that 108 | the alignment is correct as the aix version will not be able to have the 109 | p2align directive. 110 | 111 | We can enable warnings to be reported using `-w`: 112 | ```console 113 | as -w -v test.s 114 | as V7.2 115 | Assembler: 116 | test.s: line 3: Warning - The alignment of the current csect is 117 | less than the alignment specified with the .align pseudo-op. 118 | test.s: line 4: Error In Syntax 119 | ``` 120 | 121 | Compile Node.js on aix: 122 | ```console 123 | $ export PATH=/opt/ccache-3.7.4/libexec:/opt/freeware/bin:/usr/bin:/etc:/usr/sbin:/usr/ucb:/home/iojs/bin:/usr/bin/X11:/sbin:. 124 | $ export CC=gcc CXX=g++ CXX_host=g++ 125 | $ ./configure --verbose --dest-cpu=ppc64 126 | $ gmake -C out BUILDTYPE=Release V=0 127 | ``` 128 | Commenting out the .p2align diretive enable the build to pass successfully. 129 | 130 | When we configure OpenSSL specifiying the arch as `aix64-gcc`: 131 | ```console 132 | $ ./Configure aix64-gcc 133 | ``` 134 | Lets take a look at the recipe for crypto/bn/ppc64-mont-fixed: 135 | ```console 136 | $ make -n crypto/bn/ppc64-mont-fixed.s 137 | CC="gcc" /usr/bin/perl crypto/bn/asm/ppc64-mont-fixed.pl "aix64" -I. -Iinclude -Iproviders/common/include -Iproviders/implementations/include -maix64 -pthread -Wa,--noexecstack -O --help -DB_ENDIAN -DOPENSSL_PIC -DOPENSSLDIR="\"/usr/local/ssl\"" -DENGINESDIR="\"/usr/local/lib/engines-3\"" -DMODULESDIR="\"/usr/local/lib/ossl-modules\"" -DOPENSSL_BUILDING_OPENSSL -DNDEBUG -DAES_ASM -DECP_NISTP521_ASM -DECP_NISTZ256_ASM -DKECCAK1600_ASM -DOPENSSL_BN_ASM_MONT -DOPENSSL_CPUID_OBJ -DPOLY1305_ASM -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DVPAES_ASM -DX25519_ASM crypto/bn/ppc64-mont-fixed.s 138 | ``` 139 | Running this will generate crypto/bn/ppc64-mont-fixed.s. 140 | Looking at the command we can see that the make recipe is calling the perl 141 | script and passing in `aix64` 142 | 143 | When crypto/bn/asm/ppc64-mont-fixed.pl is called it will generate the assembler 144 | code and in the process the .p2align directive is added. This directive is 145 | not available in the AIX assembler hence the error we are seeing. A suggestion 146 | is to add an achitecture to OpenSSL's configuration named something like 147 | `aix64-gcc-as' which is supposed to specify that one want to use the AIX 148 | as Assembler and not GAS (gas). 149 | 150 | For this a callback could be added to crypto/perlasm/ppc-xlate.pl which check 151 | if the architecture is aix64-as and remove this directive: 152 | ```perl 153 | my $p2align = sub { 154 | my $ret = ($flavour =~ /aix64-as/) ? "" : ".p2align $line"; 155 | $ret; 156 | }; 157 | ``` 158 | This [pull request](https://github.com/openssl/openssl/pull/15638) contains a 159 | suggestion and can be tested manually using the following commands: 160 | ```console 161 | $ ./Configure aix64-gcc-as 162 | $ make -B crypto/bn/ppc64-mont-fixed.s 163 | ``` 164 | 165 | __work in progress__ 166 | -------------------------------------------------------------------------------- /notes/issues/quictls-openssl.md: -------------------------------------------------------------------------------- 1 | ### quictls/openssl 2 | This document contains notes about quictls which is a temporary fork of OpenSSL 3 | that includes QUIC Protocol support for OpenSSL 1.1.1 and 3.0.0. 4 | 5 | 6 | ### Fetching openssl 3.0 branch 7 | As this is a fork we can specify quictls as a git remote: 8 | ```console 9 | $ cd openssl 10 | $ git remote add quictls git@github.com:quictls/openssl.git 11 | $ git fetch quictls openssl-3.0.0-alpha13+quic 12 | $ git co -t quictls/openssl-3.0.0-alpha13+quic 13 | ``` 14 | 15 | ### Configure and build openssl 3.0 16 | ```console 17 | $ ./config -Werror --strict-warnings --debug --prefix=/home/danielbevenius/work/security/openssl_quic-3.0 linux-x86_64 18 | $ make clean 19 | $ make -j8 20 | $ make install_sw 21 | $ export LD_LIBRARY_PATH=/home/danielbevenius/work/security/openssl_quic-3.0/lib/ 22 | ``` 23 | 24 | ### Configure and build Node: 25 | ```console 26 | $ cd node 27 | $ ./configure --shared-openssl --shared-openssl-libpath=/home/danielbevenius/work/security/openssl_quic-3.0/lib --shared-openssl-includes=/home/danielbevenius/work/security/openssl_quic-3.0/include --shared-openssl-libname=crypto,ssl 28 | $ make -j8 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /notes/issues/tls-min-max-version-issue.md: -------------------------------------------------------------------------------- 1 | ## test-tls-min-max-version.j 2 | 3 | ```console 4 | out/Debug/node --tls-min-v1.3 /home/danielbevenius/work/nodejs/openssl/test/parallel/test-tls-cli-min-version-1.3.js 5 | test: U U TLSv1_2_method U U SSLv23_method U expect U ECONNRESET ERR_SSL_INTERNAL_ERROR 6 | (/home/danielbevenius/work/nodejs/openssl/test/parallel/test-tls-min-max-version.js:121:3) 7 | client ECONNRESET 8 | server ERR_SSL_NO_PROTOCOLS_AVAILABLE 9 | node:assert:122 10 | throw new AssertionError(obj); 11 | ^ 12 | 13 | AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: 14 | + actual - expected 15 | 16 | + 'ERR_SSL_NO_PROTOCOLS_AVAILABLE' 17 | - 'ERR_SSL_INTERNAL_ERROR' 18 | ^ 19 | at /home/danielbevenius/work/nodejs/openssl/test/parallel/test-tls-min-max-version.js:65:16 20 | at /home/danielbevenius/work/nodejs/openssl/test/common/index.js:379:15 21 | at /home/danielbevenius/work/nodejs/openssl/test/common/index.js:379:15 22 | at maybeCallback (/home/danielbevenius/work/nodejs/openssl/test/fixtures/tls-connect.js:97:7) 23 | at TLSSocket. (/home/danielbevenius/work/nodejs/openssl/test/fixtures/tls-connect.js:73:13) 24 | at TLSSocket.emit (node:events:378:20) 25 | at emitErrorNT (node:internal/streams/destroy:192:8) 26 | at emitErrorCloseNT (node:internal/streams/destroy:157:3) 27 | at processTicksAndRejections (node:internal/process/task_queues:81:21) { 28 | generatedMessage: true, 29 | code: 'ERR_ASSERTION', 30 | actual: 'ERR_SSL_NO_PROTOCOLS_AVAILABLE', 31 | expected: 'ERR_SSL_INTERNAL_ERROR', 32 | operator: 'strictEqual' 33 | } 34 | ``` 35 | 36 | If we search for `NO_PROTOCOLS_AVAILABLE` we can find that this error is raised 37 | in `ssl/statem/statem_lib.c` 38 | ```console 39 | $ lldb -- out/Debug/node --tls-min-v1.3 /home/danielbevenius/work/nodejs/openssl/test/parallel/test-tls-cli-min-version-1.3.js 40 | (lldb) br s -f statem_lib.c -l 104 41 | (lldb) r 42 | Process 1888614 stopped 43 | * thread #1, name = 'node', stop reason = breakpoint 1.1 44 | frame #0: 0x00007ffff7ad5ce8 libssl.so.3`tls_setup_handshake(s=0x0000000006071750) at statem_lib.c:104:9 45 | 92 { 46 | 93 int ver_min, ver_max, ok; 47 | 94 48 | 95 if (!ssl3_init_finished_mac(s)) { 49 | 96 /* SSLfatal() already called */ 50 | 97 return 0; 51 | 98 } 52 | 99 53 | 100 /* Reset any extension flags */ 54 | 101 memset(s->ext.extflags, 0, sizeof(s->ext.extflags)); 55 | 102 56 | 103 if (ssl_get_min_max_version(s, &ver_min, &ver_max, NULL) != 0) { 57 | -> 104 SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE); 58 | 105 return 0; 59 | 106 } 60 | 107 61 | 108 /* Sanity check that we have MD5-SHA1 if we need it */ 62 | 109 if (s->ctx->ssl_digest_methods[SSL_MD_MD5_SHA1_IDX] == NULL) { 63 | 110 int md5sha1_needed = 0; 64 | 111 65 | 112 /* We don't have MD5-SHA1 - do we need it? */ 66 | 113 if (SSL_IS_DTLS(s)) { 67 | 114 if (DTLS_VERSION_LE(ver_max, DTLS1_VERSION)) 68 | 115 md5sha1_needed = 1; 69 | 116 } else { 70 | ``` 71 | So we can see that this break point is indeed reached. 72 | 73 | ```console 74 | (lldb) expr -f d -- s->min_proto_version 75 | (const int) $15 = 772 76 | (lldb) expr -f d -- s->max_proto_version 77 | (const int) $14 = 771 78 | ``` 79 | We can find these versions in `include/openssl/tls1.h`: 80 | ```c 81 | # define TLS1_VERSION 0x0301 82 | # define TLS1_1_VERSION 0x0302 83 | # define TLS1_2_VERSION 0x0303 84 | # define TLS1_3_VERSION 0x0304 85 | # ifndef OPENSSL_NO_DEPRECATED_3_0 86 | # define TLS_MAX_VERSION TLS1_3_VERSION 87 | # endif 88 | ``` 89 | And TLS1_3_VERSION is 772: 90 | ```console 91 | (lldb) expr -f d -- 0x0304 92 | (int) $16 = 772 93 | ``` 94 | And TLS1_2_VERSION is 771: 95 | ```console 96 | (lldb) expr -f d -- 0x0303 97 | (int) $12 = 771 98 | ``` 99 | So we can see that the `min_proto_version` is `TLS1_3_VERSION` and 100 | `max_proto_version` is `TLS1_2_VERSION `. So this does not look right but we 101 | need to keep in mind that this is test that is expected to fail, only that 102 | the error message is not the same in OpenSSL 3.0. 103 | 104 | Lets call ssl_get_min_max_version and see what is happening: 105 | ```console 106 | (lldb) expr -i0 -- ssl_get_min_max_version(s, &ver_min, &ver_max, NULL) 107 | 108 | ``` 109 | In our case TSL_ANY_VERSION will be taken 110 | ```c 111 | int ssl_get_min_max_version(const SSL *s, int *min_version, int *max_version, 112 | int *real_max) 113 | { 114 | ... 115 | switch (s->method->version) { 116 | default: 117 | *min_version = *max_version = s->version; 118 | if (!ossl_assert(real_max == NULL)) 119 | return ERR_R_INTERNAL_ERROR; 120 | return 0; 121 | case TLS_ANY_VERSION: 122 | table = tls_version_table; 123 | break; 124 | case DTLS_ANY_VERSION: 125 | table = dtls_version_table; 126 | break; 127 | } 128 | 129 | 130 | ... 131 | /* Fail if everything is disabled */ 132 | if (version == 0) 133 | return SSL_R_NO_PROTOCOLS_AVAILABLE; 134 | 135 | return 0; 136 | } 137 | ``` 138 | In our case is looks like we should be alright just changing the error 139 | message for OpenSSL3. So in the cases where this is checked we can add 140 | something like: 141 | ```js 142 | test(U, U, 'TLSv1_1_method', U, U, 'SSLv23_method', 143 | U, 'ECONNRESET', common.hasOpenSSL3 ? 144 | "ERR_SSL_NO_PROTOCOLS_AVAILABLE" : 'ERR_SSL_INTERNAL_ERROR'); 145 | ``` 146 | Adding this allows the tests to pass. 147 | -------------------------------------------------------------------------------- /notes/issues/tls-renegotiation-issue.md: -------------------------------------------------------------------------------- 1 | ## Node.js TLS Renegotiation attach issue 2 | This was discovered when linking against the latest openssl/openssl upstream 3 | master: 4 | ```console 5 | $ ~/work/security/openssl_build_master/bin/openssl version -b -v 6 | OpenSSL 3.0.0-alpha17-dev (Library: OpenSSL 3.0.0-alpha17-dev ) 7 | built on: Thu May 20 06:50:13 2021 UTC 8 | ``` 9 | 10 | The test in question is `test-https-client-renegotiation-limit.js` which 11 | fails with the following error: 12 | ```console 13 | $ out/Release/node /home/danielbevenius/work/nodejs/node-debug/test/parallel/test-https-client-renegotiation-limit.js 14 | Caught exception: Error [ERR_TLS_SESSION_ATTACK]: TLS session renegotiation attack detected 15 | Caught exception: Error [ERR_TLS_SESSION_ATTACK]: TLS session renegotiation attack detected 16 | node:events:342 17 | throw er; // Unhandled 'error' event 18 | ^ 19 | 20 | Error: 00305ED07A7F0000:error:0A000153:SSL routines:ssl3_read_bytes:no renegotiation:ssl/record/rec_layer_s3.c:1604: 21 | 22 | Emitted 'error' event on ClientRequest instance at: 23 | at TLSSocket.socketErrorListener (node:_http_client:447:9) 24 | at TLSSocket.emit (node:events:377:35) 25 | at TLSSocket._emitTLSError (node:_tls_wrap:908:10) 26 | at TLSWrap.onerror (node:_tls_wrap:429:11) { 27 | library: 'SSL routines', 28 | reason: 'no renegotiation', 29 | code: 'ERR_SSL_NO_RENEGOTIATION' 30 | } 31 | ``` 32 | Lets start by finding out where this OpenSSL error is raised. This error is 33 | defined in ssl/ssl_err.c: 34 | ```c 35 | static const ERR_STRING_DATA SSL_str_reasons[] = { 36 | ... 37 | {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_RENEGOTIATION), "no renegotiation"}, 38 | ... 39 | } 40 | ``` 41 | And we can search for SSL_R_NO_RENEGOTIATION. 42 | One place where this error is raised is in ssl/record/rec_layer_s3.c: 43 | ```c 44 | int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, 45 | size_t len, int peek, size_t *readbytes) 46 | { 47 | ... 48 | } else if (alert_descr == SSL_AD_NO_RENEGOTIATION) { 49 | /* 50 | * This is a warning but we receive it if we requested 51 | * renegotiation and the peer denied it. Terminate with a fatal 52 | * alert because if application tried to renegotiate it 53 | * presumably had a good reason and expects it to succeed. In 54 | * future we might have a renegotiation where we don't care if 55 | * the peer refused it where we carry on. 56 | */ 57 | SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, SSL_R_NO_RENEGOTIATION); 58 | return -1; 59 | } 60 | } 61 | ``` 62 | Lets start with that: 63 | ```console 64 | $ lldb -- out/Debug/node /home/danielbevenius/work/nodejs/node-debug/test/parallel/test-https-client-renegotiation-limit.js 65 | (lldb) br s -f rec_layer_s3.c -l 1604 66 | ``` 67 | This breakpoint gets hit. 68 | 69 | The OpenSSL Commit 55373bfd41 introduced `SSL_OP_ALLOW_CLIENT_RENEGOTIATION` 70 | ```text 71 | * Client-initiated renegotiation is disabled by default. To allow it, use 72 | the -client_renegotiation option, the SSL_OP_ALLOW_CLIENT_RENEGOTIATION 73 | flag, or the "ClientRenegotiation" config parameter as appropriate. 74 | ``` 75 | Adding this option to src/crypto/crypto_context.cc in SecureContext::Init will 76 | allow this test to pass: 77 | ```c++ 78 | SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_ALLOW_CLIENT_RENEGOTIATION); 79 | ``` 80 | I'm not sure this is something we want to do though. 81 | 82 | -------------------------------------------------------------------------------- /notes/issues/win-v2019-arm64.md: -------------------------------------------------------------------------------- 1 | ## win-vs2019-arm64 build issue 2 | This document containes notes about a build issue when updating Node.js 3 | to OpenSSL 3.0-beta1 and statically linking with Node.js. 4 | 5 | CI log: 6 | https://ci.nodejs.org/job/node-compile-windows/41096/nodes=win-vs2019-arm64/console 7 | 8 | The following header is not being found: 9 | ```console 10 | 18:59:41 dsa_prn.c 11 | 18:59:41 flagparser.cpp 12 | 18:59:41 package.cpp 13 | 18:59:41 dsa_ossl.c 14 | 18:59:41 dsa_pmeth.c 15 | 18:59:42 pkg_gencmn.cpp 16 | 18:59:42 toolutil.cpp 17 | 18:59:42 dso_err.c 18 | 18:59:42 dsa_vrf.c 19 | 18:59:42 dsa_sign.c 20 | 18:59:42 dso_dl.c 21 | 18:59:42 pkg_icu.cpp 22 | 18:59:42 ppucd.cpp 23 | 18:59:42 ucbuf.cpp 24 | 18:59:42 swapimpl.cpp 25 | 18:59:42 ucln_tu.cpp 26 | 18:59:42 denseranges.cpp 27 | 18:59:42 dso_dlfcn.c 28 | 18:59:42 C:\workspace\node-compile-windows\node\deps\openssl\openssl\crypto\dso\dso_dlfcn.c(28,12): fatal error C1083: Cannot open include file: 'dlfcn.h': No such file or directory [C:\workspace\node-compile-windows\node\deps\openssl\openssl.vcxproj] 29 | 18:59:42 unewdata.cpp 30 | 18:59:42 dso_lib.c 31 | 18:59:42 writesrc.cpp 32 | 18:59:42 dso_openssl.c 33 | 18:59:42 dso_vms.c 34 | 18:59:42 dso_win32.c 35 | 18:59:42 ucm.cpp 36 | 18:59:42 uparse.cpp 37 | 18:59:42 appendable.cpp 38 | 18:59:42 xmlparser.cpp 39 | 18:59:42 curve448.c 40 | 18:59:42 bmpset.cpp 41 | 18:59:42 uoptions.cpp 42 | 18:59:42 brkeng.cpp 43 | 18:59:42 ucmstate.cpp 44 | 18:59:42 brkiter.cpp 45 | 18:59:43 bytesinkutil.cpp 46 | 18:59:43 f_impl32.c 47 | 18:59:43 bytestream.cpp 48 | 18:59:43 bytestrie.cpp 49 | 18:59:43 bytestriebuilder.cpp 50 | 18:59:43 bytestrieiterator.cpp 51 | 18:59:43 f_impl64.c 52 | 18:59:43 characterproperties.cpp 53 | 18:59:43 caniter.cpp 54 | 18:59:43 chariter.cpp 55 | 18:59:43 charstr.cpp 56 | 18:59:43 cstring.cpp 57 | 18:59:43 cstr.cpp 58 | 18:59:43 cmemory.cpp 59 | 18:59:43 cwchar.cpp 60 | 18:59:43 dictbe.cpp 61 | 18:59:43 dictionarydata.cpp 62 | 18:59:43 dtintrv.cpp 63 | 18:59:43 edits.cpp 64 | 18:59:43 errorcode.cpp 65 | 18:59:43 filterednormalizer2.cpp 66 | ``` 67 | 68 | The issue here is that when we generate the platform specific headers for 69 | OpenSSL the no-asm headers template was incorrect, actually it was not used at 70 | all and the asm header template was used which does not include VC-WIN64-ARM. 71 | This should only be in the no-asm headers template. I've updated the template 72 | and updated generate_headers.pl in an attempt to fix this. 73 | Did that work? 74 | 75 | 76 | -------------------------------------------------------------------------------- /notes/modes.md: -------------------------------------------------------------------------------- 1 | # Modes of operation 2 | The reason for using modes is that when we have block ciphers that operate on 3 | using a specific block size. But unless the data we want to encrypt is exactly 4 | that size we need to break it up into smaller chunks and encrypt each one. This 5 | document contains notes on the various techniques that can be used for this. 6 | 7 | ``` 8 | Modes of operation 9 | / \ 10 | / \ 11 | Deterministic / \ Probabilistic 12 | / \ 13 | +-----+ Block / \ Stream 14 | | ECB | Ciphers / \ Ciphers 15 | +-----+ / \ 16 | +-----+ +-----+ 17 | | CBC | | OBF | 18 | +-----+ +-----+ 19 | +-----+ 20 | | CFB | 21 | +-----+ 22 | +--------------+ 23 | | Counter Mode | 24 | +--------------+ 25 | ``` 26 | 27 | ## Electronic Code Book (ECB) 28 | This is the simplest mode where the input text/data is split into blocks equal 29 | to the ciphers length, and then each block is encrypted separately. Blocks that 30 | are smaller than the ciphers size can be padded. 31 | ``` 32 | Encryption 33 | 34 | M₁ M₂ M₃ 35 | ↓ ↓ ↓ 36 | E E E 37 | ↓ ↓ ↓ 38 | C₁ C₂ C₃ 39 | ``` 40 | Now if the input messages happen to be the same then the cipher text will be 41 | identical. This is very performant as all blocks can be processed in parallel. 42 | 43 | ``` 44 | Decryption 45 | 46 | M₁ M₂ M₃ 47 | ↑ ↑ ↑ 48 | E E E 49 | ↑ ↑ ↑ 50 | C₁ C₂ C₃ 51 | ``` 52 | 53 | 54 | ## Cipher Block Chaining (CBC) 55 | ``` 56 | Encryption 57 | M₁ M₂ M₃ 58 | ↓ ↓ ↓ 59 | IV-->x +->x +->x X=xor 60 | ↓ | ↓ | ↓ 61 | E | E | E 62 | | | | | | 63 | +-+ +-+ | 64 | ↓ ↓ ↓ 65 | C₁ C₂ C₃ 66 | ``` 67 | This fixes the problem with the same input not generating identical outputs. 68 | Decryption works in the opposite order, so C₁ is passed through the decription 69 | algorithm used and then xor:ed with the IV which was sent with the message. 70 | The IV is used so that the if the same first block is passed into the cipher it 71 | will not generate an identical output block. 72 | 73 | One downside of CBC is that it is no longer possible to encrypt in parallel, 74 | since to encrypt message block 2 we first have to encrypt message block 1 and 75 | so on. 76 | 77 | ``` 78 | Decryption 79 | 80 | M₁ M₂ M₃ 81 | ↑ ↑ ↑ 82 | IV-->x +->x +->x X=xor 83 | ↑ | ↑ | ↑ 84 | E | E | E 85 | | | | | | 86 | +-+ +-+ | 87 | ↑ ↑ ↑ 88 | C₁ C₂ C₃ 89 | ``` 90 | During decryption there is also an issue where it is possible for an attacker 91 | to manipulate bits in cipher block 2 which would directly effect the decryption 92 | of message block 3. Changing cipher block 2 will mess up the decryption of that 93 | message, but there are attacks like padding attacks that are possible with this 94 | mode of operation. 95 | 96 | ## Counter Mode (CTR) 97 | Is also known as CM, Integer Counter Mode, and Segmented Counter Mode (SIC). 98 | 99 | ``` 100 | n = nounce (number unique to a specific communication) 101 | 102 | Encryption 103 | 104 | n+1 n+2 n+3 105 | ↓ ↓ ↓ 106 | E E E 107 | ↓ ↓ ↓ 108 | n₁ n₂ n₃ nₓ = 128 random bits 109 | ↓ ↓ ↓ X = xor 110 | m₁->x m₂->x m₃->x 111 | ↓ ↓ ↓ 112 | C₁ C₂ C₃ 113 | ``` 114 | What we now have is that each message will produce a unique/different cipher 115 | text and it is possible to "jump" a position in the chain and decrypt that as 116 | there are no dependencies on earlier decryption. We just have to do 117 | `nounce + n`. 118 | 119 | ``` 120 | Decryption 121 | 122 | n+1 n+2 n+3 123 | ↓ ↓ ↓ 124 | E E E 125 | ↓ ↓ ↓ 126 | n₁ n₂ n₃ nₓ = 128 random bits 127 | ↓ ↓ ↓ 128 | m₁<-x m₂<-x m₃<-x 129 | ↑ ↑ ↑ 130 | C₁ C₂ C₃ 131 | ``` 132 | Both notice that an attacker could change the ciphertext which will effect 133 | the message block (plain text). 134 | 135 | ## Counter with CBC-MAC (CCM) 136 | This type of encryption combines counter mode encryption with a message 137 | authentication code (MAC). What it is trying to do is to address the issue 138 | in CTR where an attacker could change a cipher text block which could directly 139 | affect the decrypted message block. Here a MAC is computed on the ciphertext 140 | and will only decrypt if the ciphertext has not been changed. Doing it this way 141 | is called encrypt-then-mac. The encryption stage produces encrypted ciphertext 142 | blocks and also a tag which is a mac for these cipher blocks. 143 | 144 | ``` 145 | Key 146 | ↓ 147 | m -> AES --> Cipher Text --> 148 | ↑ MAC 149 | IV 150 | ``` 151 | 152 | 153 | ### Galios Counter Mode 154 | In the previous section we mentioned that an attacker could manipulate the 155 | cipher text block which would impact the message block decrypted and there 156 | would be no way for the receiver to know that that was not the correct 157 | information. 158 | 159 | 160 | 161 | ## Cipher Feedback Mode (CFB) 162 | -------------------------------------------------------------------------------- /notes/node_openssl_config.md: -------------------------------------------------------------------------------- 1 | ### Node --openssl-config issue 2 | This document contains notes about Node's command line option `--openssl-config` 3 | which is used to specify the OpenSSL configuration file. There has been a report 4 | that this option does not work with OpenSSL 3.0. 5 | 6 | First `OPENSSL_MODULES`, and `LD_LIBRARY_PATH` need to be specified as a 7 | environment variables, and they can be exported or set for the command to be 8 | run. This is only required if OpenSSL is installed to a non-default location. 9 | 10 | Here we will export it to make the command to be executed a little shorter. 11 | ```console 12 | $ export OPENSSL_MODULES=/home/danielbevenius/work/security/openssl_quic-3.0/lib/ossl-modules/ 13 | $ export LD_LIBRARY_PATH=/home/danielbevenius/work/security/openssl_quic-3.0/lib 14 | ``` 15 | 16 | There is an environment variable named `OPENSSL_CONF` that can be set which 17 | we know works: 18 | ```console 19 | $ export OPENSSL_CONF=/home/danielbevenius/work/security/openssl_quic-3.0/ssl/openssl.cnf 20 | ``` 21 | With these set we can verify that FIPS can be enabled: 22 | ```console 23 | $ ./node --enable-fips -p 'crypto.getFips()' 24 | 1 25 | ``` 26 | Now, if we unset OPENSSL_CONF and instead specify `--openssl-config` 27 | ```console 28 | $ unset OPENSSL_CONF 29 | $ ./node --openssl-config=/home/danielbevenius/work/security/openssl_quic-3.0/ssl/openssl.cnf --enable-fips -p 'crypto.getFips()' 30 | 1 31 | ``` 32 | Actually, that seems to work. 33 | -------------------------------------------------------------------------------- /notes/padding.md: -------------------------------------------------------------------------------- 1 | ### Padding 2 | This document contains notes about padding used in crypto. 3 | 4 | ### RSA padding 5 | Just to recap about RSA and that it will split the message into blocks of 6 | plaintext. For example this could be 16 byte blocks (so 128 bits in total). 7 | But the input message might not be an even multiple of this size so padding is 8 | added to ensure this. 9 | 10 | For example, if we need to pad on byte: 11 | ``` 12 | 7 6 5 4 3 2 1 0 13 | Block size 8: DD OF 0F CB F1 AA 97 14 | Padding : DD OF 0F CB F1 AA 97 01 15 | ``` 16 | Two bytes: 17 | ``` 18 | 7 6 5 4 3 2 1 0 19 | Block size 8: DD OF 0F CB F1 AA 97 20 | Padding : DD OF 0F CB F1 AA 02 02 21 | ``` 22 | And if more are needed they will be 03, 04 and so on. One situation that is 23 | possible is that we have a valid 01 as the last character in which case a 24 | complete padding byte is appended to the message: 25 | ``` 26 | 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 27 | Block size 8: DD OF 0F CB F1 AA 97 01 28 | Padding : DD OF 0F CB F1 AA 97 01 08 08 08 08 08 08 08 08 29 | 30 | Block n-1 Block n 31 | 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 32 | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ 33 | Ciphertext | | | | | | | | x| | | | | | | | | | 34 | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ 35 | | | 36 | +----+ Decrypt 37 | | ↓ 38 | +--+--+--+--+--+--+--+--+ | +--+--+--+--+--+--+--+--+ 39 | | ?| ?| ?| ?| ?| ?| ?| ?| | | ?| ?| ?| ?| ?| ?| ?| ?| 40 | +--+--+--+--+--+--+--+--+ | +--+--+--+--+--+--+--+--+ 41 | | | 42 | +--------------------------+ ? ^ x = 01 43 | ↓ 44 | 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 45 | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ 46 | Plaintext | | | | | | | | | | | | | | | | |01| 47 | +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ 48 | 49 | ``` 50 | Notice that we are able to get the plain text of the last value in block n-1. 51 | This is possible as the last block will first be decrypted and then it will be 52 | xored with the previous ciphertext (which in this case we control). Now if we 53 | can guess the value of x such that it equals 0x01. Doing this would make the 54 | padding valied and no error reported by the oracle (server or whatever program 55 | is decrypting the data). 56 | 57 | ### Optimal Asymmetric Encryption Padding (OAEP or sometimes RSA-OAEP). 58 | For this we need the message to be encrypted `K` and two hash functions and also 59 | a PRNG `R`. 60 | 61 | The encoded message will be formed as: 62 | ``` 63 | M = H || 00 . . . 00 || 01 || K 64 | ``` 65 | So our message K needs to be small enough to fit into a byte array with h bytes 66 | then as many 00 as needed (what are these for?) and then a 01 separator followed 67 | by the message. But also notice that the final result will have a 00 prepended 68 | to it. 69 | 70 | 71 | This message is then processed like this: 72 | ``` 73 | +---+ +-------------------+ 74 | | R | |H||0000...00001||K | (as many 00 as required ending with 01) 75 | +---+ +-------------------+ 76 | | +-----+ | 77 | +-->|Hash1|-------->^ 78 | | +-----+ | 79 | | | 80 | | +-----+ | 81 | ^<--|Hash1|<--------+ 82 | | +-----+ | 83 | ↓ ↓ 84 | +---+ +-------------------+ 85 | | R | |H||00000...0001||K | 86 | +---+ +-------------------+ 87 | | 88 | +-----+ 89 | ↓ 90 | +---------------------------------+ 91 | P= |00| | | 92 | +---------------------------------+ 93 | 94 | P = 00 || M || R 95 | ``` 96 | 97 | ``` 98 | m = 256 bytes for 2048-bit RSA 99 | h = 32 SHA-256 as Hash2 100 | 101 | m - n - 1 102 | 256 - 32 - 1 = 233 bytes for M 103 | 104 | 245 - 2*32 - 2 = 190 (bytes available for the message) 105 | ``` 106 | Remember we have two hash functions, therefore the *2. The -2 is for the 01 107 | separator but I don't understand why this would be two and not one. There is 108 | only one 01 separator as far as I can tell. What am I missing? 109 | 110 | And I was not sure what `||` meant, but looking at the notation section in 111 | https://tools.ietf.org/html/rfc3447#section-2 I see it means it's a 112 | concatenation operator. This section is also useful if you come accross variable 113 | names that might not be obvious at first in OpenSSL. 114 | Notice the 01 which is used as a separator above that is appended above which 115 | is why we have to subtract two from M. I think this is due to M first having 116 | a 01 separator before the message K, and also that P will have 00 prepended to 117 | it. 118 | 119 | 120 | ### Probabilistic Signature Scheme (PSS) 121 | Is similar to what OEAP provides for RSA encryption, PSS provides for RSA 122 | Signatures. The goals is to make message signing more secure. 123 | 124 | ``` 125 | +---------+ +-------------------+ +---+ +-----------+ +---+ 126 | | Hash(M) |--->| Padding Algorithm |--->| P |--->| RSA(n, d) |--->| S | 127 | +---------+ +-------------------+ +---+ +-----------+ +---+ 128 | ``` 129 | So we take the message that we want to sign and create a hash of it as the first 130 | step. This allows us to sign a message of any length as the hash will output 131 | the same length message regardless. Using SHA-256 the length would be 256 bits. 132 | 133 | Like OAEP PSS also requires a PRNG and two hash functions. 134 | 135 | ### PKCS #1v 1.5 padding 136 | This was used in TLS version prior to 1.2. 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /notes/providers.md: -------------------------------------------------------------------------------- 1 | #### Providers 2 | There are different providers for different algorithm implementations. These 3 | can be configured programatically or via a configuration file. 4 | There are currently 4 provider implementations: 5 | 6 | * Default 7 | 8 | * Legacy 9 | Algorithms in the legacy provider include MD2, MD4, MDC2, RMD160, CAST5, 10 | BF (Blowfish), IDEA, SEED, RC2, RC4, RC5 and DES (but not 3DES). 11 | 12 | * FIPS 13 | 14 | * null 15 | Contains nothing and can be used to the default provider is not automatically 16 | loaded. 17 | 18 | Example of loading a provider: 19 | ```c 20 | OSSL_PROVIDER_load(NULL, "default"); 21 | ``` 22 | 23 | OSSL_PROVIDER struct can be found in crypto/provider_core.c: 24 | ```c 25 | struct ossl_provider_st { 26 | /* Flag bits */ 27 | unsigned int flag_initialized:1; 28 | unsigned int flag_activated:1; 29 | unsigned int flag_fallback:1; /* Can be used as fallback */ 30 | unsigned int flag_activated_as_fallback:1; 31 | 32 | /* OpenSSL library side data */ 33 | CRYPTO_REF_COUNT refcnt; 34 | CRYPTO_RWLOCK *refcnt_lock; /* For the ref counter */ 35 | CRYPTO_REF_COUNT activatecnt; 36 | CRYPTO_RWLOCK *activatecnt_lock; /* For the activate counter */ 37 | 38 | char *name; 39 | char *path; 40 | DSO *module; 41 | OSSL_provider_init_fn *init_function; 42 | STACK_OF(INFOPAIR) *parameters; 43 | OSSL_LIB_CTX *libctx; /* The library context this instance is in */ 44 | struct provider_store_st *store; /* The store this instance belongs to */ 45 | #ifndef FIPS_MODULE 46 | /* 47 | * In the FIPS module inner provider, this isn't needed, since the 48 | * error upcalls are always direct calls to the outer provider. 49 | */ 50 | int error_lib; /* ERR library number, one for each provider */ 51 | # ifndef OPENSSL_NO_ERR 52 | ERR_STRING_DATA *error_strings; /* Copy of what the provider gives us */ 53 | # endif 54 | #endif 55 | 56 | /* Provider side functions */ 57 | OSSL_FUNC_provider_teardown_fn *teardown; 58 | OSSL_FUNC_provider_gettable_params_fn *gettable_params; 59 | OSSL_FUNC_provider_get_params_fn *get_params; 60 | OSSL_FUNC_provider_get_capabilities_fn *get_capabilities; 61 | OSSL_FUNC_provider_self_test_fn *self_test; 62 | OSSL_FUNC_provider_query_operation_fn *query_operation; 63 | 64 | /* 65 | * Cache of bit to indicate of query_operation() has been called on 66 | * a specific operation or not. 67 | */ 68 | unsigned char *operation_bits; 69 | size_t operation_bits_sz; 70 | CRYPTO_RWLOCK *opbits_lock; 71 | 72 | /* Provider side data */ 73 | void *provctx; 74 | }; 75 | ``` 76 | Notice that some of the unsigned in fields are being declared with a specific 77 | bit field size. 78 | 79 | There is an example of a custom provider in [provider.c](../provider.c). 80 | 81 | The provider implementation is in [cprovider.c](../cprovider.c) 82 | -------------------------------------------------------------------------------- /notes/rsa.md: -------------------------------------------------------------------------------- 1 | ### Rivest Shamir and Aldeman (RSA) 2 | Is actually two algoritms, one for asymmetric key encryption (key exchange) and 3 | one for digital signatures (like signing public-key certificates). 4 | 5 | Is a public key encryption technique developed in 1978 by the people mentioned 6 | in the title. It is an asymmetric system that uses a private and a public key. 7 | RSA is somewhat slow and it not used to encrypt data in a communication, but 8 | instead it is used to encrypt a symmetric key which is then used to encrypt data. 9 | 10 | It starts by selecting two prime numbers `p` and `q` and taking the product of 11 | them: 12 | ``` 13 | N = pq 14 | 15 | p = 2, q = 7 16 | N = 2*7 = 14 17 | ``` 18 | `N` will become our modulus. 19 | 20 | What are the values that don't have common factors with our modulus (14)? 21 | ``` 22 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 23 | 1, x, 3, x, 5, x, x, x, 9, x, 11, x, 13, x 24 | 1, 3, 5, 9, 11, 13 25 | ``` 26 | So we have 6 values that don't have common factors with 14. 27 | 28 | This can also be calculated using: 29 | ``` 30 | L = (q - 1) * (p - 1) 31 | L = (2 - 1) * (7 - 1) 32 | L = (1) * (6) = 6 33 | ``` 34 | So `L` will be `6`. 35 | 36 | For encryption we will have a key that consists of a tuple, where one value 37 | will be the modulus we calculated above: 38 | ``` 39 | (?, 14) 40 | ``` 41 | The encryption key must be a value between 1 and the value of 'L', which in our 42 | case gives us 4 values to choose from, `2, 3, 4, 5`. 43 | The value we choose must not share any other factors besides 1 with L(6), and 44 | our modulus(14). `5` is the only option in our case: 45 | ``` 46 | (5, 14) 47 | ``` 48 | This is the public key exponent which we will see later is used as the exponent 49 | that we raise the value to be encrypted (m) to: 50 | ``` 51 | m⁵ mod(14) = encrypted value 52 | ``` 53 | 54 | Decryption also uses a tuple with one being the modules as well: 55 | ``` 56 | (?, 14) 57 | ``` 58 | To calculate the private key value we use the following formula: 59 | ``` 60 | D * E % L = 1 61 | ``` 62 | And with concrete values: 63 | ``` 64 | D * 5 % 6 = 1 65 | ``` 66 | Options for D: 67 | ``` 68 | 5, 11, 17, 23, 29, 35, ... 69 | ``` 70 | Let choose `11`: 71 | ``` 72 | 11 * 5 % 6 = 1 73 | 55 % 6 = 1 74 | ``` 75 | This values is called the private exponent because in much the same way as 76 | the public exponent the encrypted value(e) will be raised to this value: 77 | ``` 78 | y^d mod n = (x^e)^d mod n = x^ed mod n = x 79 | ``` 80 | Where y is the encrypted value, which is the same as the plain text x raised 81 | to the encryption exponent e mod n. So we can write the decryption as the 82 | plain text raised to encryption exponent times the decryption exponent mod n. 83 | 84 | ``` 85 | e¹¹ mod(14) = decrypted value 86 | ``` 87 | 88 | Encryption and decryption: 89 | ``` 90 | message = 2 91 | m⁵ mod(14) = encrypted value 92 | 2⁵ mod(14) = 4 93 | 94 | encrypted value = 4 95 | 4¹¹ mod(14) = 2 96 | ``` 97 | And notice that 4 in our case is m⁵, which is 2⁵ mod 14 so we can write this as: 98 | ``` 99 | (m⁵)¹¹ mod (14) 100 | m⁵*¹¹ mod (14) 101 | m⁵*¹¹ mod (14) = m⁵⁵ mod (14) = 102 | ``` 103 | 104 | Now, there are issues with the what we have done above, first encrypting the 105 | same plaintext multiple times will produce the same cipher text. There is also 106 | an issue where if we multiply two identical ciphertexts with each other mod n we 107 | will get the plain text. 108 | ``` 109 | y1 × y2 mod n = x1^e × x2^e mod n = (x1 × x2)^e mod n 110 | ``` 111 | 112 | To avoid this we use padding. 113 | Optimal Asymmetric Encryption Padding (OAEP or sometimes RSA-OAEP). 114 | 115 | In this case we create a bit string as large as the modulus, so a bit string 116 | of size 14 in our current example. This is padded before encrypion. The bits 117 | need to be random or otherwise they would just be the same problem as before, 118 | so OAEP needs some form of pseudorandom number generator. 119 | 120 | I've see the following in books/blogs etc describing padding: 121 | ``` 122 | M = H || 00 . . . 00 || 01 || K 123 | ``` 124 | And I was not sure what `||` meant, but looking at the notation section in 125 | https://tools.ietf.org/html/rfc3447#section-2 I see it means it's a 126 | concatenation operator. This section is also useful if you come accross variable 127 | names that might not be obvious at first in OpenSSL. 128 | Notice the 01 which is used as a separator above that is appended above which 129 | is why we have to subtract two from M. TODO: explain and verify this. 130 | 131 | Length of an octet is 8 so we are talking about byte length. 132 | 133 | ### RSA-PSS 134 | Is one of the signature schemes in RSA. PSS stands for Probabilistic Signture 135 | Scheme. PSS requires parameters like the hash function to be used and the mask 136 | generation function (MGF). PSS is randomized and will create a different 137 | signature each time. Is a signature scheme with appendix which means that it 138 | does not sign the message itself but instead signs a hash of the message. This 139 | hash is produced by the hash/algorithm/message digest function. 140 | 141 | ### RSA small messages 142 | If the messages being sent are smaller than the modulus the modulus operation 143 | can be avoided as it does not do anything. For example: 144 | ``` 145 | 2^1 mod 4 = 2 146 | ``` 147 | We need to have a message that is greater than the modulus size. This is where 148 | various padding schemes come into play with RSA. 149 | 150 | ### PKCSv1 (Public-Key Cryptography Standard version 1) 151 | A part of this standard includes RSA encryption, decryption, encoding/padding 152 | schemes. The padding scheme can be used with RSA to avoid the small messages 153 | problem discussed above. 154 | For example, say we have an AES 128 bit key that we want to encrypt and send to 155 | a receiver. This will need to be expanded to 2048 bits and this is done using 156 | padding. For example; 157 | ``` 158 | 2048 bits 159 | +----+------+------+------------------------+ 160 | |Op |Random| 0xFF | msg | 161 | +-----------+------+------------------------+ 162 | Bits: 16 r 16 128 163 | 164 | Op = Operation, 0001 is for signatures, and 0002 is for public key encryption 165 | Random = random number but must not contain any 0xFF. 166 | ``` 167 | The idea here is that this is what is passed into the RSA encryption function 168 | and sent to the other side. 169 | The receiver will decrypt the ciphertext and check the first bits 0x0002 to 170 | make sure that it has the correct padding format, and if it does not an error 171 | might be returned. And here in lies the issue. This lets an attacker that can 172 | intercept a ciphertext to modify the ciphertext and send it to the server, if 173 | the server does returns an error the attacker has a way of finding out if the 174 | changes pass encryption or not (if the server returns an error or not). 175 | 176 | 177 | ### RSA Optimal Asymmetric Encryption Padding 178 | An improvement over PKCS#1 with regards to its padding scheme. 179 | ``` 180 | G: hash function that returns g bits 181 | H: hash function that returns h bits 182 | r: random nonce of g bits 183 | ``` 184 | -------------------------------------------------------------------------------- /notes/testing.md: -------------------------------------------------------------------------------- 1 | ### Testing in OpenSSL 2 | 3 | Make the test in question: 4 | ```console 5 | $ make test/ossl_store_test 6 | ``` 7 | 8 | Running a single test case: 9 | ```console 10 | $ ./test/ossl_store_test -help 11 | $ ./test/ossl_store_test -test test_store_attach 12 | ``` 13 | 14 | Listing all tests: 15 | ```console 16 | $ make list-tests 17 | ``` 18 | 19 | Run a single test: 20 | ```console 21 | $ make test TESTS=test_store 22 | ``` 23 | 24 | ### run_tests.pl 25 | This is a program that runs tests, both written in perl which can call the 26 | app openssl for example, and unit test written in c. 27 | 28 | List all tests: 29 | ```console 30 | $ env SRCTOP=. perl test/run_tests.pl list 31 | ``` 32 | Run a single test: 33 | ```console 34 | $ env SRCTOP=. BLDTOP=. perl test/run_tests.pl test_ossl_store 35 | ``` 36 | `test_store` is a recipe found in test/recipes/66-test_ossl_store.t: 37 | ```console 38 | use OpenSSL::Test::Simple; 39 | use OpenSSL::Test qw/:DEFAULT srctop_file/; 40 | 41 | setup("test_ossl_store"); 42 | 43 | plan tests => 1; 44 | 45 | ok(run(test(["ossl_store_test", "-in", srctop_file("test", "testrsa.pem")]))); 46 | ``` 47 | `test` can be found in `util/perl/OpenSSL/Test.pm` and the program will be 48 | the unit test written in c, which in this case would be 49 | `./../test/ossl_store_test`. 50 | 51 | Verbose output: 52 | ```console 53 | $ env SRCTOP=. BLDTOP=. VERBOSE=yes perl test/run_tests.pl test_rsapss 54 | ``` 55 | 56 | The main function for the test framework is defined in `test/testutil/main.c`. 57 | 58 | #### Address Sanitizer 59 | Install: 60 | ```console 61 | $ sudo dnf install libasan libasan-static 62 | ``` 63 | And debuginfo can be optionally install using: 64 | ```console 65 | $ sudo dnf debuginfo-install libasan 66 | ``` 67 | 68 | Configure build: 69 | ```console 70 | $ ./config --strict-warnings --debug --prefix=/home/danielbevenius/work/security/openssl_build_master linux-x86_64 -fsanitize=address 71 | ``` 72 | 73 | Running tests with asan: 74 | ```console 75 | $ make _tests 76 | ``` 77 | 78 | ### Undefined Behaviour Sanitizer (ubsan) 79 | ```console 80 | $ sudo dnf install libubsan 81 | ``` 82 | 83 | Configure build: 84 | ```console 85 | $ ./config --strict-warnings --debug --prefix=/home/danielbevenius/work/security/openssl_build_master linux-x86_64 -fsanitize=address enable-ubsan 86 | ``` 87 | 88 | #### Adding a test 89 | Find an appropriate test in the test directory and look for the `setup_tests` 90 | function. Add the new test using one of the macros in test/testutil.h, for example: 91 | ```c 92 | ADD_TEST(test_store_attach); 93 | ``` 94 | Next add the test implementation: 95 | ```c 96 | static int test_store_attach(void) 97 | { 98 | int ret; 99 | OSSL_STORE_CTX* ctx = OSSL_STORE_attach(NULL, "file", libctx, NULL, 100 | NULL, NULL, NULL, NULL); 101 | return 0; 102 | } 103 | ``` 104 | 105 | #### Printing out an error in lldb 106 | ```console 107 | (lldb) expr ERR_peek_error() 108 | (unsigned long) $1 = 369098857 109 | 110 | 111 | (lldb) expr ERR_reason_error_string($1) 112 | (const char *) $2 = 0x00000000006c2024 "unregistered scheme" 113 | 114 | (lldb) expr ERR_reason_error_string(ERR_peek_error()) 115 | ``` 116 | 117 | ### md-nits 118 | First install markdownling: 119 | ```console 120 | $ gem install mdl 121 | ``` 122 | 123 | Run the md-nits target: 124 | ```console 125 | $ make md-nits 126 | ``` 127 | 128 | ### Enable REF_PRINT 129 | Enable `REF_PRINT`in OpenSSL build: 130 | ```console 131 | $ ./config --debug --prefix=/home/danielbevenius/work/security/openssl_build_master linux-x86_64 -DREF_PRINT 132 | $ make clean 133 | $ make -j8 134 | $ make install_sw 135 | ``` 136 | -------------------------------------------------------------------------------- /notes/tls.md: -------------------------------------------------------------------------------- 1 | ### TLS 2 | In the TLS protocol the Record Layer takes care of transporting and encryption 3 | and extensions handle other aspects (for example server name SNI). 4 | 5 | There are four subprotocols: 6 | #### Handshake protocol 7 | In a full handshake the client and server will exchange capabilities and agree 8 | on connection parameters. Validation of certificates will take place. 9 | Both parties will agree on a master secret to be used to protect the session. 10 | ``` 11 | Client Server 12 | ClientHello ---------------------> 13 | <--------------------- ServerHello 14 | [<-------------------- Certificate] 15 | [<-------------------- ServerKeyExchange] 16 | <--------------------- ServerHelloDone 17 | ClientKeyExchange---------------------> 18 | [ChangeCipherSpec--------------------->] 19 | Finished ---------------------> 20 | [<-------------------- ChangeCipherSpec] 21 | <-------------------- Finished 22 | ``` 23 | 24 | ### ClientHello 25 | Is the first message sent in a new Handshake 26 | Lets take a look at a client hello. This was sent by invoking a test in node.js: 27 | ```console 28 | $ env NODE_DEBUG_NATIVE=tls ./node test/parallel/test-tls-session-cache.js 29 | ``` 30 | Using wireshark we can inspect the ClientHello message: 31 | ``` 32 | Transport Layer Security 33 | TLSv1 Record Layer: Handshake Protocol: Client Hello 34 | Content Type: Handshake (22) 35 | Version: TLS 1.0 (0x0301) 36 | Length: 109 37 | Handshake Protocol: Client Hello 38 | Handshake Type: Client Hello (1) 39 | Length: 105 40 | Version: TLS 1.0 (0x0301) 41 | Random: 35e6a7452268dbdb04cd4398f62946f38b21ca142993a269… 42 | Session ID Length: 0 43 | Cipher Suites Length: 18 44 | Cipher Suites (9 suites) 45 | Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a) 46 | Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) 47 | Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039) 48 | Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009) 49 | Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) 50 | Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033) 51 | Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) 52 | Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) 53 | Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff) 54 | Compression Methods Length: 1 55 | Compression Methods (1 method) 56 | Extensions Length: 46 57 | Extension: server_name (len=10) 58 | Extension: ec_point_formats (len=4) 59 | Extension: supported_groups (len=12) 60 | Extension: encrypt_then_mac (len=0) 61 | Extension: extended_master_secret (len=0) 62 | ``` 63 | Notice the cipher suites being sent from the client to the server. And the client 64 | is using TLS 1.0. 65 | 66 | A cipher suite is a complete set of algorithms that are needed for a secure a 67 | connection in TLS. This includes a key exchange algorithm, an authentication 68 | algorithm, bulk encryption algorithm, and a message authentication algorithm. 69 | ``` 70 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 71 | ``` 72 | Here `TLS` is the protocol. `EDCHE` is the key exchange algorithm. `RSA` is the 73 | authentication algorithm. `AES_256_CBC` is the bulk encryption algorithm. `SHA` 74 | is the message authentication algorithm. 75 | 76 | The client sends the ciphers suites that it supports to the server as we can 77 | see above and the servers responds with a chosen suite that it supports. If the 78 | server does not have a match a secure connection will not be established. 79 | 80 | #### Change cipher spec protocol 81 | TODO 82 | 83 | #### Application data protocol 84 | TODO 85 | 86 | #### Alert protocol 87 | TODO 88 | -------------------------------------------------------------------------------- /notes/webcrypto.md: -------------------------------------------------------------------------------- 1 | ### WebCrypto 2 | https://www.w3.org/TR/WebCryptoAPI/ 3 | https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API 4 | 5 | Is a JavaScript API for performing basic crypto operations like hashing, 6 | signature generation and verification, encryption/decryption. 7 | There are both cryptographic functions and key management functions. 8 | 9 | TLS will help with encrypting data on the wire between a client and a server 10 | but after that it can be stored decrypted on the server. 11 | 12 | SubtleCrypto is the interface exposed and provides functions like: 13 | ```js 14 | SubtleCrypto.encrypt() 15 | SubtleCrypto.decrypt() 16 | SubtleCrypto.sign() 17 | SubtleCrypto.verify() 18 | SubtleCrypto.digest() 19 | SubtleCrypto.generateKey() 20 | SubtleCrypto.deriveKey() 21 | SubtleCrypto.deriveBits() 22 | SubtleCrypto.importKey() 23 | SubtleCrypto.exportKey() 24 | SubtleCrypto.wrapKey() 25 | SubtleCrypto.unwrapKey() 26 | ``` 27 | 28 | ### CryptoKey 29 | Represents a key in WebCrypto. 30 | Has the following properties: 31 | 32 | #### type 33 | A String of one of the following values `secret`, `private`, `public`. 34 | `secret`is used for symmetric algorithms and `private` and `public` are used 35 | with asymmetric algorithms. 36 | 37 | #### extractable 38 | Specifies if this key can be extracted using `exportKey` or `wrapKey`. If this 39 | value is false and those functions are called an exception will be thrown. 40 | 41 | #### algorithm 42 | Is an object which can be one of the following types: 43 | `AesKeyGenParams`, `RsaHashedKeyGenParams`, `EcKeyGenParams`, `HmacKeyGenParams`. 44 | 45 | #### usages 46 | `usages` is an Array with values of one or more of the following values: 47 | ``` 48 | encrypt: The key may be used to encrypt messages. 49 | decrypt: The key may be used to decrypt messages. 50 | sign: The key may be used to sign messages. 51 | verify: The key may be used to verify signatures. 52 | deriveKey: The key may be used in deriving a new key. 53 | deriveBits: The key may be used in deriving bits. 54 | wrapKey: The key may be used to wrap a key. 55 | unwrapKey: The key may be used to unwrap a key 56 | 57 | ### AesKeyGenParams 58 | Has two properties `name` and `length`. 59 | 60 | `name` can be one of `AES-CBC`, `AES-CTR`, `AES-GCM`, or `AES-KW` (Key-Wrap) 61 | which specifies the mode of operation. 62 | 63 | `length` is the number of bits to generate and can be `128`, `192` or `256`. 64 | 65 | ### RsaHashedKeyGenParams 66 | Are the parameters used when generating a RSA based key and is used for the 67 | algoritms `RSASSA-PKCS1-v1_5`, `RSA-PSS`, or `RSA-OAEP`. 68 | 69 | This object has the following properties: 70 | `name` which is a string and one of `RSASSA-PKCS1-v1_5`, `RSA-PSS`, or `RSA-OAEP`. 71 | 72 | `modulusLength` the length of the RSA modulus and should be at least 2048. 73 | 74 | `publicExponent` is of type Uint8Array. 75 | 76 | `hash` is the name of the digest function to use and can be one of `SHA-256`, 77 | `SHA-384`, or `SHA-512`. 78 | 79 | ### EcKeyGenParams 80 | Uses as parameters when the algorithm is either `ECDSA` or `ECDH`. 81 | 82 | `name` can be one of `ECDSA` or `ECDH`. 83 | 84 | `namedCurve` the elliptic curve to use and can be one of `P-256`, `P-384`, or 85 | `P-512`. 86 | 87 | 88 | ### HmacKeyGenParams 89 | Used when the algorithm is `HMAC`. 90 | 91 | `name` should be `HMAC`. 92 | 93 | `hash` is the name of the digest function to use and can be one of `SHA-1`, 94 | `SHA-256`, `SHA-384`, or `SHA-512`. 95 | 96 | `length` is an optional length in bits of the key. 97 | 98 | ### exportKey 99 | Takes a `CryptoKey` and produces it in a portable external format: 100 | ```js 101 | const result = crypto.subtle.exportKey(format, key); 102 | ``` 103 | The key is not encrypted, if that is desired then use `wrapKey` instead. 104 | 105 | ### importKey 106 | Takes a key in external format and returns it as a `CryptoKey`. 107 | ```js 108 | crypto.subtle.importKey(format, 109 | keyData, 110 | algorithm, 111 | extractable, 112 | keyUsages); 113 | ``` 114 | `format` can be `raw`, `pkcs8`, `spki`, or `jwk` (JSON Web Key format). 115 | 116 | 117 | `keyUsages` can be any of the values specified in CryptoKey.usages. 118 | 119 | The name subtle is to reflect that many of the algorithms have subtle usage 120 | requirements in order to provide the required algorithmic security guarantees. 121 | 122 | ```js 123 | window.crypto.getRandomValues(); 124 | ``` 125 | 126 | ### wrapKey 127 | This function will call exportKey and then encrypt the result from that call. 128 | This produces a key in a portable format that is encrypted. 129 | ```js 130 | const result = crypto.subtle.wrapKey(format, key, wrappingKey, wrapAlgo); 131 | ``` 132 | 133 | ### encrypt 134 | Encrypts the plaintext (`data` below) using the specified algorithm and key: 135 | ```js 136 | const result = crypto.subtle.encrypt(algorithm, key, data); 137 | ``` 138 | The result is a promise what when fulfilled will be an ArrayBuffer. 139 | 140 | -------------------------------------------------------------------------------- /openssl.cnf: -------------------------------------------------------------------------------- 1 | openssl_conf = openssl_init 2 | 3 | .include fips.cnf 4 | 5 | [openssl_init] 6 | providers = prov 7 | 8 | [prov] 9 | fips = fipsinstall 10 | 11 | -------------------------------------------------------------------------------- /pem_key_read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static int passwd_callback(char* buf, int size, int rwflag, void* u) { 12 | const char* passphrase = (char*) u; 13 | if (passphrase != NULL) { 14 | size_t buflen = (size_t) size; 15 | size_t len = strlen(passphrase); 16 | if (buflen < len) 17 | return -1; 18 | memcpy(buf, passphrase, len); 19 | return len; 20 | } 21 | return -1; 22 | } 23 | 24 | int main(int arc, char *argv[]) { 25 | printf("OpenSSL pem_read_bio example\n"); 26 | OSSL_PROVIDER* provider; 27 | provider = OSSL_PROVIDER_load(NULL, "default"); 28 | UI_METHOD* ui_method = UI_UTIL_wrap_read_pem_callback(passwd_callback, 0); 29 | OSSL_LIB_CTX* libctx = OSSL_LIB_CTX_new(); 30 | 31 | BIO* bio = BIO_new_file("./rsa_private.pem", "r"); 32 | 33 | EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, NULL, "undefined"); 34 | if (key) 35 | printf("read private key successfully\n"); 36 | else 37 | printf("cound not read private key!\n"); 38 | 39 | ERR_print_errors_fp(stdout); 40 | 41 | assert(key != NULL); 42 | 43 | 44 | BIO_free(bio); 45 | //OSSL_PROVIDER_unload(provider); 46 | OSSL_LIB_CTX_free(libctx); 47 | exit(EXIT_SUCCESS); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /private.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int arc, char *argv[]) { 10 | ERR_load_crypto_strings(); 11 | OpenSSL_add_all_algorithms(); 12 | OPENSSL_no_config(); 13 | 14 | EVP_PKEY* pkey = EVP_PKEY_new(); 15 | printf("pkey id = %d\n", EVP_PKEY_id(pkey)); 16 | printf("pkey base id = %d\n", EVP_PKEY_base_id(pkey)); 17 | printf("pkey type = %d\n", EVP_PKEY_type(EVP_PK_RSA)); 18 | EVP_PKEY_free(pkey); 19 | 20 | BIO *bout; 21 | bout = BIO_new_fp(stdout, BIO_NOCLOSE); 22 | 23 | int bits = 1024; 24 | BIGNUM* exponent = BN_new(); 25 | BN_set_word(exponent, 3); 26 | RSA* rsa = RSA_new(); 27 | int r = RSA_generate_key_ex(rsa, bits, exponent, NULL); 28 | 29 | int p = EVP_PKEY_print_private(bout, pkey, 0, NULL); 30 | printf("p = %d\n", p); 31 | 32 | BN_free(exponent); 33 | RSA_free(rsa); 34 | EVP_cleanup(); 35 | CRYPTO_cleanup_all_ex_data(); 36 | ERR_free_strings(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /provider.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void error_and_exit(const char* msg) { 7 | printf("%s\n", msg); 8 | char buf[256]; 9 | int err = ERR_get_error(); 10 | ERR_error_string_n(err, buf, sizeof(buf)); 11 | printf("errno: %d, %s\n", err, buf); 12 | exit(EXIT_FAILURE); 13 | } 14 | 15 | /* 16 | * To run this example OpenSSL need to be able to find the shared library 17 | * libcprovider.so which is created in the current directory when running 18 | * $ make provider 19 | * 20 | * Setting OPENSSL_MODULES to the current directory will allow for this example 21 | * to be run: 22 | * $ env OPENSSL_MODULES=$PWD ./provider 23 | */ 24 | int main(int argc, char** argv) { 25 | printf("Provider example\n"); 26 | OSSL_PROVIDER* provider; 27 | 28 | provider = OSSL_PROVIDER_load(NULL, "default"); 29 | if (provider == NULL) { 30 | printf("Failed to load Default provider\n"); 31 | exit(EXIT_FAILURE); 32 | } 33 | printf("Default Provider name: %s\n", OSSL_PROVIDER_get0_name(provider)); 34 | 35 | OSSL_PROVIDER* custom_provider = OSSL_PROVIDER_load(NULL, "libcprovider"); 36 | if (custom_provider == NULL) 37 | error_and_exit("Could not create custom provider"); 38 | 39 | 40 | printf("Custom Provider name: %s\n", OSSL_PROVIDER_get0_name(custom_provider)); 41 | 42 | OSSL_PROVIDER_unload(provider); 43 | exit(EXIT_SUCCESS); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char** argv) { 8 | printf("RAND_status example\n"); 9 | for (;;) { 10 | int status = RAND_status(); 11 | printf("status: %d\n", status); 12 | if (status != 0) { 13 | break; 14 | } 15 | 16 | int ret = RAND_poll(); 17 | printf("ret: %d\n", ret); 18 | if (ret == 0) { 19 | break; 20 | } 21 | } 22 | 23 | exit(EXIT_SUCCESS); 24 | } 25 | -------------------------------------------------------------------------------- /rand_status.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * This needs to be run using OPENSSL_CONF so that the OpenSSL configuration 12 | * file in this directory is used: 13 | * 14 | * $ env OPENSSL_CONF=$PWD/openssl.cnf OPENSSL_MODULES=path/to/ossl-modules ./rand_status 15 | * 16 | * For example: 17 | * $ env OPENSSL_CONF=$PWD/openssl.cnf OPENSSL_MODULES=/home/danielbevenius/work/security/openssl_build_master/lib/ossl-modules ./rand_status 18 | */ 19 | int main(int argc, char** argv) { 20 | 21 | int r = RAND_status(); 22 | printf("rand_status: %d\n", r); 23 | ERR_print_errors_fp(stderr); 24 | 25 | exit(EXIT_SUCCESS); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /random_bytes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void handleErrors(void); 8 | 9 | void print_bytes(unsigned char* buf, int size) { 10 | for (int i = 0; i < size; i++) { 11 | printf("%d", buf[i]); 12 | } 13 | printf("\n"); 14 | } 15 | 16 | int main(int arc, char *argv[]) { 17 | ERR_load_crypto_strings(); 18 | OPENSSL_no_config(); 19 | // Seed the random generator 20 | RAND_poll(); 21 | 22 | int size = 8; 23 | unsigned char buf[size]; 24 | RAND_bytes(buf, size); 25 | print_bytes(buf, size); 26 | 27 | RAND_bytes(buf, size); 28 | print_bytes(buf, size); 29 | 30 | CRYPTO_cleanup_all_ex_data(); 31 | ERR_free_strings(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /rsa.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void error_and_exit(const char* msg) { 10 | printf("%s\n", msg); 11 | char buf[256]; 12 | int err = ERR_get_error(); 13 | ERR_error_string_n(err, buf, sizeof(buf)); 14 | printf("errno: %d, %s\n", err, buf); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int main(int arc, char *argv[]) { 19 | printf("RSA example\n"); 20 | 21 | int modulus_bits = 512; 22 | const uint32_t exponent = 0x10001; 23 | 24 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); 25 | if (ctx == NULL) { 26 | error_and_exit("Could not create a context for RSA_PSS"); 27 | } 28 | 29 | if (EVP_PKEY_keygen_init(ctx) <= 0) { 30 | error_and_exit("Could not initialize the RSA context"); 31 | } 32 | 33 | if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, modulus_bits) <= 0) { 34 | error_and_exit("EVP_PKEY_CTX_set_rsa_keygen_bits failed"); 35 | } 36 | 37 | BIGNUM* exponent_bn = BN_new(); 38 | BN_set_word(exponent_bn, exponent); 39 | if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, exponent_bn) <= 0) { 40 | error_and_exit("EVP_PKEY_CTX_set_rsa_keygen_pubexp failed"); 41 | } 42 | 43 | EVP_PKEY* pkey = NULL; 44 | if (EVP_PKEY_keygen(ctx, &pkey) != 1) { 45 | error_and_exit("EVP_PKEY_keygen failed"); 46 | } 47 | 48 | // So we have our key generated. We can now use it to encrypt 49 | 50 | // Create and initialize a new context for encryption. 51 | EVP_PKEY_CTX* enc_ctx = EVP_PKEY_CTX_new(pkey, NULL); 52 | if (EVP_PKEY_encrypt_init(enc_ctx) <= 0) { 53 | error_and_exit("EVP_PKEY_encrypt_init failed"); 54 | } 55 | // Any algorithm specific control operations can be performec now before 56 | if (EVP_PKEY_CTX_set_rsa_padding(enc_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { 57 | error_and_exit("EVP_PKEY_CTX_set_rsa_padding failed"); 58 | } 59 | 60 | unsigned char* in = (unsigned char*) "Bajja"; 61 | size_t outlen; 62 | unsigned char* out; 63 | 64 | printf("Going to encrypt: %s\n", in); 65 | // Determine the size of the output 66 | if (EVP_PKEY_encrypt(enc_ctx, NULL, &outlen, in, strlen ((char*)in)) <= 0) { 67 | error_and_exit("EVP_PKEY_encrypt failed"); 68 | } 69 | printf("Determined ciphertext to be of length: %d) is:\n", outlen); 70 | 71 | out = OPENSSL_malloc(outlen); 72 | 73 | if (EVP_PKEY_encrypt(enc_ctx, out, &outlen, in, strlen ((char*)in)) <= 0) { 74 | error_and_exit("EVP_PKEY_encrypt failed"); 75 | } 76 | 77 | printf("Encrypted ciphertext (len:%d) is:\n", outlen); 78 | BIO_dump_fp(stdout, (const char*) out, outlen); 79 | 80 | EVP_PKEY_CTX* dec_ctx = EVP_PKEY_CTX_new(pkey, NULL); 81 | if (EVP_PKEY_decrypt_init(dec_ctx) <= 0) { 82 | error_and_exit("EVP_PKEY_encrypt_init failed"); 83 | } 84 | 85 | if (EVP_PKEY_CTX_set_rsa_padding(dec_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { 86 | error_and_exit("EVP_PKEY_CTX_set_rsa_padding failed"); 87 | } 88 | 89 | unsigned char* dout; 90 | size_t doutlen; 91 | if (EVP_PKEY_decrypt(dec_ctx, NULL, &doutlen, out, outlen) <= 0) { 92 | error_and_exit("EVP_PKEY_decrypt get length failed"); 93 | } 94 | 95 | printf("Determimed plaintext to be of length: %d:\n", doutlen); 96 | dout = OPENSSL_malloc(doutlen); 97 | if (!dout) { 98 | error_and_exit("OPENSSL_malloc failed"); 99 | } 100 | 101 | if (EVP_PKEY_decrypt(dec_ctx, dout, &doutlen, out, outlen) <= 0) { 102 | error_and_exit("EVP_PKEY_decrypt failed"); 103 | } 104 | 105 | printf("Decrypted Plaintext is:\n"); 106 | BIO_dump_fp(stdout, (const char*) dout, doutlen); 107 | 108 | EVP_PKEY_CTX_free(ctx); 109 | exit(EXIT_SUCCESS); 110 | } 111 | -------------------------------------------------------------------------------- /rsa_cert.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEAjCCAuqgAwIBAgIUf4Z4DKj5kJW60NE+9PaucYFlft8wDQYJKoZIhvcNAQEL 3 | BQAwgbAxCzAJBgNVBAYTAlVLMRQwEgYDVQQIDAtBY2tuYWNrIEx0ZDETMBEGA1UE 4 | BwwKUmh5cyBKb25lczEQMA4GA1UECgwHbm9kZS5qczEdMBsGA1UECwwUVGVzdCBU 5 | TFMgQ2VydGlmaWNhdGUxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRIwEAYDVQQDDAls 6 | b2NhbGhvc3QxGzAZBgkqhkiG9w0BCQEWDGFsZXhAYXViLmRldjAgFw0xOTA2Mjgy 7 | MTM2NDhaGA8yMjkzMDQxMTIxMzY0OFowgbAxCzAJBgNVBAYTAlVLMRQwEgYDVQQI 8 | DAtBY2tuYWNrIEx0ZDETMBEGA1UEBwwKUmh5cyBKb25lczEQMA4GA1UECgwHbm9k 9 | ZS5qczEdMBsGA1UECwwUVGVzdCBUTFMgQ2VydGlmaWNhdGUxFDASBgNVBAsMC0Vu 10 | Z2luZWVyaW5nMRIwEAYDVQQDDAlsb2NhbGhvc3QxGzAZBgkqhkiG9w0BCQEWDGFs 11 | ZXhAYXViLmRldjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALfcWIiK 12 | J7HAt78/wNnHkeyoWWZQ7v+W8nud5wlU3Cp1ndrHmOlAHSnq7F+p46/Nw3eTlXtQ 13 | Vv8Cb6eRI1kwBmGxbMJTZng+OHnRBjPd/Qei6vv/IgZK04vJhjeGAsrYrxNuGCNA 14 | +F2TD35C0qWm9svx8uA40CgatU4WdFAZyvvSIV9+ybv2aBmEpUyBiIc8momAYe8K 15 | 2QaD3MyBLunrf5DdlZ520VLZGExfe4IHL+YfoQ6VEI0FtGYDjHE3PJ/kZBqSLdP4 16 | jP204yN08/4LBXYuoR3KWYG6KTy+t9NveogcsooEAjyVc3brBa0DeQ3gvs0/5xsq 17 | UJGWpy2+GbKUsfUCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsF 18 | AAOCAQEAD2FBwUO9iV4VBrpTdUEd0Y39ajJsdbbnNkJ/N1ZbJgdymCLfVpzCqB+s 19 | qRjpq9JqGtcxwzPG7GGu+OIXCGMfeMzFkk2cjLeZic5uKcynFgru4bzrhGdb26Wq 20 | s8rQeXFOO6aRdpTVvIO+Vq5goRTXJhbtEzA9efmYWIOXcL5WDYhwApOc8rwfz9fm 21 | q8VZCW+KK23EU3gfyOcO14E0Al/K6lewX15K1Hh4P8cSnFtjtCqRRWmQi9JfdasS 22 | A0YJd8rN47dplRylTtXu5VFKL+XXa/jmlzsgtxBHX14onpVKqfGCvCLqj+AeZA3Y 23 | iX4iQjxnLr5DRtykOz+bKEYgX8AV8g== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /rsa_data_too_large.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void error_and_exit(const char* msg) { 10 | printf("%s\n", msg); 11 | char buf[256]; 12 | int err = ERR_get_error(); 13 | ERR_error_string_n(err, buf, sizeof(buf)); 14 | printf("errno: %d, %s\n", err, buf); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int main(int arc, char *argv[]) { 19 | printf("RSA example\n"); 20 | 21 | //int modulus_bits = 512; 22 | //int modulus_bits = 4096; 23 | int modulus_bits = 2048; 24 | const uint32_t exponent = 0x10001; 25 | 26 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); 27 | if (ctx == NULL) { 28 | error_and_exit("Could not create a context for RSA"); 29 | } 30 | 31 | if (EVP_PKEY_keygen_init(ctx) <= 0) { 32 | error_and_exit("Could not initialize the RSA context"); 33 | } 34 | 35 | if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, modulus_bits) <= 0) { 36 | error_and_exit("EVP_PKEY_CTX_set_rsa_keygen_bits failed"); 37 | } 38 | 39 | BIGNUM* exponent_bn = BN_new(); 40 | BN_set_word(exponent_bn, exponent); 41 | if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, exponent_bn) <= 0) { 42 | error_and_exit("EVP_PKEY_CTX_set_rsa_keygen_pubexp failed"); 43 | } 44 | 45 | EVP_PKEY* pkey = NULL; 46 | if (EVP_PKEY_keygen(ctx, &pkey) != 1) { 47 | error_and_exit("EVP_PKEY_keygen failed"); 48 | } 49 | 50 | // So we have our key generated. We can now use it to encrypt 51 | 52 | // Create and initialize a new context for encryption. 53 | EVP_PKEY_CTX* enc_ctx = EVP_PKEY_CTX_new(pkey, NULL); 54 | if (EVP_PKEY_encrypt_init(enc_ctx) <= 0) { 55 | error_and_exit("EVP_PKEY_encrypt_init failed"); 56 | } 57 | 58 | if (EVP_PKEY_CTX_set_rsa_padding(enc_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { 59 | error_and_exit("EVP_PKEY_CTX_set_rsa_padding failed"); 60 | } 61 | 62 | const EVP_MD* digest = EVP_get_digestbyname("sha256"); 63 | 64 | if (EVP_PKEY_CTX_set_rsa_oaep_md(enc_ctx, digest) <= 0) { 65 | error_and_exit("EVP_PKEY_CTX_set_rsa_oaep_md failed"); 66 | } 67 | 68 | if (EVP_PKEY_CTX_set_rsa_mgf1_md(enc_ctx, digest) <= 0) { 69 | error_and_exit("EVP_PKEY_CTX_set_rsa_mgf1_md failed"); 70 | } 71 | 72 | /* 73 | if (EVP_PKEY_CTX_set0_rsa_oaep_label(enc_ctx, label, label_len) <= ) { 74 | error_and_exit("EVP_PKEY_CTX_set_rsa_oaep_label failed"); 75 | } 76 | */ 77 | 78 | unsigned char* in = (unsigned char*) "{'key_ops':['encrypt'],'ext':true,'kty':'RSA','n':'pxk47EU_QTbyNixQ6hfiZUjOuCOp7P3AwCC37YUnLdDyZoDttNB7F3ka01sk5OECC1C6Vm34zf1l5AwjEdYplGDf0ARsZTKRLF1YusA5gLf06YoXb7B6Sevd87Pr4fW_hwZNtURHic2a4gJngKuPuDrUEs4SAE9OkdmnrSreWLs-lGxAQlt37plZPN8sddq03kwEd9XWLzDEJWQVy6IeUld_9Wgg75105nyA4yBbaCVpIRtmzZz4Hfr5cKwBy8eHMXePxrDM7C0nlkpIJSZ9P8sLJYLLjSrGFsfrclECeUyn9BQo0q_wxeZa2f16Z6zExQKNBriI-t6ihNItsnN88w','e':'AQAB','alg':'RSA-OAEP-256'} "; 79 | size_t outlen; 80 | unsigned char* out; 81 | 82 | printf("Going to encrypt: %s, len: %zu\n", in, strlen((char*)in)); 83 | // Determine the size of the output 84 | if (EVP_PKEY_encrypt(enc_ctx, NULL, &outlen, in, strlen ((char*)in)) <= 0) { 85 | error_and_exit("EVP_PKEY_encrypt failed"); 86 | } 87 | printf("Determined ciphertext to be of length: %zu:\n", outlen); 88 | 89 | out = OPENSSL_malloc(outlen); 90 | 91 | if (EVP_PKEY_encrypt(enc_ctx, out, &outlen, in, strlen ((char*)in)) <= 0) { 92 | error_and_exit("EVP_PKEY_encrypt failed"); 93 | } 94 | 95 | printf("Encrypted ciphertext (len:%zu) is:\n", outlen); 96 | BIO_dump_fp(stdout, (const char*) out, outlen); 97 | 98 | EVP_PKEY_CTX* dec_ctx = EVP_PKEY_CTX_new(pkey, NULL); 99 | if (EVP_PKEY_decrypt_init(dec_ctx) <= 0) { 100 | error_and_exit("EVP_PKEY_encrypt_init failed"); 101 | } 102 | 103 | if (EVP_PKEY_CTX_set_rsa_padding(dec_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { 104 | error_and_exit("EVP_PKEY_CTX_set_rsa_padding failed"); 105 | } 106 | 107 | //const EVP_MD* digest = EVP_get_digestbyname("sha256"); 108 | 109 | if (EVP_PKEY_CTX_set_rsa_oaep_md(dec_ctx, digest) <= 0) { 110 | error_and_exit("EVP_PKEY_CTX_set_rsa_oaep_md failed"); 111 | } 112 | 113 | if (EVP_PKEY_CTX_set_rsa_mgf1_md(dec_ctx, digest) <= 0) { 114 | error_and_exit("EVP_PKEY_CTX_set_rsa_mgf1_md failed"); 115 | } 116 | 117 | unsigned char* dout; 118 | size_t doutlen; 119 | if (EVP_PKEY_decrypt(dec_ctx, NULL, &doutlen, out, outlen) <= 0) { 120 | error_and_exit("EVP_PKEY_decrypt get length failed"); 121 | } 122 | 123 | printf("Determimed plaintext to be of length: %zu:\n", doutlen); 124 | dout = OPENSSL_malloc(doutlen); 125 | if (!dout) { 126 | error_and_exit("OPENSSL_malloc failed"); 127 | } 128 | 129 | if (EVP_PKEY_decrypt(dec_ctx, dout, &doutlen, out, outlen) <= 0) { 130 | error_and_exit("EVP_PKEY_decrypt failed"); 131 | } 132 | 133 | printf("Decrypted Plaintext is:\n"); 134 | BIO_dump_fp(stdout, (const char*) dout, doutlen); 135 | 136 | EVP_PKEY_CTX_free(ctx); 137 | exit(EXIT_SUCCESS); 138 | } 139 | -------------------------------------------------------------------------------- /rsa_private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEAt9xYiIonscC3vz/A2ceR7KhZZlDu/5bye53nCVTcKnWd2seY 3 | 6UAdKersX6njr83Dd5OVe1BW/wJvp5EjWTAGYbFswlNmeD44edEGM939B6Lq+/8i 4 | BkrTi8mGN4YCytivE24YI0D4XZMPfkLSpab2y/Hy4DjQKBq1ThZ0UBnK+9IhX37J 5 | u/ZoGYSlTIGIhzyaiYBh7wrZBoPczIEu6et/kN2VnnbRUtkYTF97ggcv5h+hDpUQ 6 | jQW0ZgOMcTc8n+RkGpIt0/iM/bTjI3Tz/gsFdi6hHcpZgbopPL630296iByyigQC 7 | PJVzdusFrQN5DeC+zT/nGypQkZanLb4ZspSx9QIDAQABAoIBAQCS2erYu8gyoGPi 8 | 3E/zYgQ6ishFAZWzDWSFubwD5wSm4SSAzvViL/RbO6kqS25xR569DmLRiHzD17VI 9 | mJMsNECUnPrqR2TL256OJZaXrNHh3I1lUwVhEzjeKMsL4/ys+d70XPXoiocVblVs 10 | moDXEIGEqa48ywPvVE3Fngeuxrsq3/GCVBNiwtt0YjAOZxmKEh31UZdHO+YI+wNF 11 | /Z8KQCPscN5HGlR0SIQOlqMANz49aKStrevdvjS1UcpabzDEkuK84g3saJhcpAhb 12 | pGFmAf5GTjkkhE0rE1qDF15dSqrKGfCFtOjUeK17SIEN7E322ChmTReZ1hYGfoSV 13 | cdFntUINAoGBAPFKL5QeJ6wZu8R/ru11wTG6sQA0Jub2hGccPXpbnPrT+3CACOLI 14 | JTCLy/xTKW3dqRHj/wZEe+jUw88w7jwGb1BkWr4BI8tDvY9jQLP1jyuLWRfrxXbp 15 | 4Z0oeBBwBeCI/ZG7FIvdDTqWxn1aj3Tmh6s4ByqEdtwrrrJPcBUNl01fAoGBAMMR 16 | 3RGE/ca6X6xz6kgUD6TtHVhiiRJK1jm/u+q0n7i/MBkeDgTZkHYS7lPc0yIdtqaI 17 | Plz5yzwHnAvuMrv8LSdkjwioig2yQa3tAij8kXxqs7wN5418DMV2s1OJBrPthYPs 18 | bv4im2iI8V63JQS4ZMYQbckq8ABYccTpOnxXDy0rAoGBAKkvzHa+QjERhjB9GyoT 19 | 1FhLQIsVBmYSWrp1+cGO9V6HPxoeHJzvm+wTSf/uS/FmaINL6+j4Ii4a6gWgmJts 20 | I6cqBtqNsAx5vjQJczf8KdxthBYa0sXTrsfktXNJKUXMqIgDtp9vazQ2vozs8AQX 21 | FPAAhD3SzgkJdCBBRSTt97ZfAoGAWAziKpxLKL7LnL4dzDcx8JIPIuwnTxh0plCD 22 | dCffyLaT8WJ9lXbXHFTjOvt8WfPrlDP/Ylxmfkw5BbGZOP1VLGjZn2DkH9aMiwNm 23 | bDXFPdG0G3hzQovx/9fajiRV4DWghLHeT9wzJfZabRRiI0VQR472300AVEeX4vgb 24 | rDBn600CgYEAk7czBCT9rHn/PNwCa17hlTy88C4vXkwbz83Oa+aX5L4e5gw5lhcR 25 | 2ZuZHLb2r6oMt9rlD7EIDItSs+u21LOXWPTAlazdnpYUyw/CzogM/PN+qNwMRXn5 26 | uXFFhmlP2mVg2EdELTahXch8kWqHaCSX53yvqCtRKu/j76V31TfQZGM= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /rsa_pss.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void error_and_exit(const char* msg) { 10 | printf("%s\n", msg); 11 | char buf[256]; 12 | int err = ERR_get_error(); 13 | ERR_error_string_n(err, buf, sizeof(buf)); 14 | printf("errno: %d, %s\n", err, buf); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | int main(int arc, char *argv[]) { 19 | printf("RSA_PSS example\n"); 20 | 21 | OSSL_PROVIDER* provider = OSSL_PROVIDER_load(NULL, "default"); 22 | int modulus_bits = 512; 23 | 24 | const char* md_name = "sha256"; 25 | const EVP_MD* md = EVP_get_digestbyname(md_name); 26 | 27 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA_PSS, NULL); 28 | if (ctx == NULL) { 29 | error_and_exit("Could not create a context for RSA_PSS"); 30 | } 31 | 32 | if (EVP_PKEY_keygen_init(ctx) <= 0) { 33 | error_and_exit("Could not initialize the RSA context"); 34 | } 35 | 36 | if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, modulus_bits) <= 0) { 37 | printf("%d", EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, modulus_bits)); 38 | error_and_exit("EVP_PKEY_CTX_set_rsa_keygen_bits failed"); 39 | } 40 | 41 | if (EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx, md) <= 0) { 42 | error_and_exit("EVP_PKEY_CTX_set_rsa_pss_keygen_md failed"); 43 | } 44 | 45 | EVP_PKEY* pkey = NULL; 46 | if (EVP_PKEY_keygen(ctx, &pkey) != 1) { 47 | error_and_exit("EVP_PKEY_keygen failed"); 48 | } 49 | 50 | const char* message = "bajja"; 51 | 52 | // Sign 53 | unsigned char sig[1024]; 54 | unsigned int sig_len = 0; 55 | EVP_MD_CTX* s_mdctx = EVP_MD_CTX_new(); 56 | EVP_SignInit_ex(s_mdctx, md, NULL); 57 | EVP_SignUpdate(s_mdctx, message, strlen(message)); 58 | EVP_SignFinal(s_mdctx, sig, &sig_len, pkey); 59 | printf("Digest is: "); 60 | for (int i = 0; i < sig_len; i++) { 61 | printf("%02x", sig[i]); 62 | } 63 | printf("\n"); 64 | 65 | // Verify 66 | EVP_MD_CTX* v_mdctx = EVP_MD_CTX_new(); 67 | if (!EVP_DigestInit_ex(v_mdctx, md, NULL)) { 68 | error_and_exit("EVP_DigestInit_ex failed"); 69 | } 70 | 71 | if (!EVP_DigestUpdate(v_mdctx, "bajja", strlen(message))) { 72 | error_and_exit("EVP_DigestInit_ex failed"); 73 | } 74 | 75 | unsigned char m[1024]; 76 | unsigned int m_len = 0; 77 | if (!EVP_DigestFinal_ex(v_mdctx, m, &m_len)) { 78 | error_and_exit("EVP_DigestInit_ex failed"); 79 | } 80 | 81 | EVP_PKEY_CTX* vctx = EVP_PKEY_CTX_new(pkey, NULL); 82 | if (!EVP_PKEY_verify_init(vctx)) { 83 | error_and_exit("EVP_verify_init failed"); 84 | } 85 | 86 | if (!EVP_PKEY_CTX_set_signature_md(vctx, md)) { 87 | error_and_exit("EVP_verify_init failed"); 88 | } 89 | 90 | if(!EVP_PKEY_verify(vctx, sig, sig_len, m, m_len)) { 91 | printf("Could not verify signature!\n"); 92 | } else { 93 | printf("Verified signature!\n"); 94 | } 95 | 96 | 97 | EVP_PKEY_CTX_free(ctx); 98 | EVP_MD_CTX_free(s_mdctx); 99 | EVP_MD_CTX_free(v_mdctx); 100 | OSSL_PROVIDER_unload(provider); 101 | exit(EXIT_SUCCESS); 102 | } 103 | -------------------------------------------------------------------------------- /rsa_sign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void error_and_exit(const char* msg) { 11 | printf("%s\n", msg); 12 | char buf[256]; 13 | int err = ERR_get_error(); 14 | ERR_error_string_n(err, buf, sizeof(buf)); 15 | printf("errno: %d, %s\n", err, buf); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | EVP_PKEY* create_pkey(EVP_PKEY_CTX* ctx, const EVP_MD* md) { 20 | printf("md_type: %d, size: %d\n", EVP_MD_type(md), EVP_MD_size(md)); 21 | 22 | int modulus_bits = 512; 23 | 24 | if (ctx == NULL) { 25 | error_and_exit("Could not create a context for RSA"); 26 | } 27 | 28 | if (EVP_PKEY_keygen_init(ctx) <= 0) { 29 | error_and_exit("Could not initialize the RSA context"); 30 | } 31 | 32 | if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, modulus_bits) <= 0) { 33 | error_and_exit("EVP_PKEY_CTX_set_rsa_keygen_bits failed"); 34 | } 35 | 36 | if (EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx, md) <= 0) { 37 | error_and_exit("EVP_PKEY_CTX_set_rsa_pss_keygen_md failed"); 38 | } 39 | 40 | if (EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx, md) <= 0) { 41 | error_and_exit("EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md failed"); 42 | } 43 | 44 | if (EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(ctx, 16) <= 0) { 45 | error_and_exit("EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen failed"); 46 | } 47 | 48 | // If the following block in uncommented the setting of the message 49 | // digest later will succeed. This was actually done in Node.js's code base 50 | // but has now been removed, which surfaced this issue. 51 | /* 52 | if (EVP_PKEY_keygen_init(ctx) <= 0) { 53 | error_and_exit("Could not initialize the RSA context"); 54 | } 55 | */ 56 | 57 | EVP_PKEY* pkey = NULL; 58 | if (EVP_PKEY_keygen(ctx, &pkey) != 1) { 59 | error_and_exit("EVP_PKEY_keygen failed"); 60 | } 61 | 62 | return pkey; 63 | } 64 | 65 | void sign(unsigned char* sig, size_t siglen, EVP_PKEY* pkey, const EVP_MD* md) { 66 | unsigned char* message = (unsigned char*) "Hello Node.js world!"; 67 | int message_len = strlen((char*) message); 68 | printf("Going to sign: %s, len: %d\n", message, message_len); 69 | 70 | EVP_PKEY_CTX* sign_ctx = NULL; 71 | EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); 72 | 73 | if (EVP_DigestSignInit(mdctx, &sign_ctx, md, NULL, pkey) <= 0) { 74 | error_and_exit("EVP_DigestSignInit failed"); 75 | } 76 | 77 | printf("MD type for mdctx (sign): %d\n", EVP_MD_type(EVP_MD_CTX_md(mdctx))); 78 | 79 | if (EVP_PKEY_CTX_set_rsa_padding(sign_ctx, RSA_PKCS1_PSS_PADDING) <= 0) { 80 | error_and_exit("EVP_PKEY_CTX_set_rsa_padding failed"); 81 | } 82 | 83 | // Get the output length into siglen 84 | if (EVP_DigestSign(mdctx, NULL, &siglen, NULL, 0) <= 0) { 85 | error_and_exit("EVP_DigestSign get length failed"); 86 | } 87 | printf("Determined signature to be of length: %d:\n", siglen); 88 | 89 | sig = OPENSSL_malloc(siglen); 90 | 91 | // Now sign using the retrievied length 92 | if (EVP_DigestSign(mdctx, sig, &siglen, message, message_len) <= 0) { 93 | error_and_exit("EVP_DigestSign failed"); 94 | } 95 | 96 | printf("Signature (len:%d) is:\n", siglen); 97 | BIO_dump_fp(stdout, (const char*) sig, siglen); 98 | } 99 | 100 | void verify(unsigned char* sig, size_t siglen, EVP_PKEY* pkey, const EVP_MD* md) { 101 | EVP_MD_CTX* ver_md_ctx = EVP_MD_CTX_new(); 102 | 103 | if (EVP_DigestInit_ex(ver_md_ctx, md, NULL) <= 0) { 104 | error_and_exit("EVP_DigestInit_ex failed"); 105 | } 106 | 107 | unsigned char* message = (unsigned char*) "Hello Node.js world!"; 108 | int message_len = strlen((char*) message); 109 | if (EVP_DigestUpdate(ver_md_ctx, message, message_len) <= 0) { 110 | error_and_exit("EVP_DigestUpdate failed"); 111 | } 112 | 113 | unsigned char m[EVP_MAX_MD_SIZE]; 114 | unsigned int m_len; 115 | 116 | if (EVP_DigestFinal_ex(ver_md_ctx, m, &m_len) <= 0) { 117 | error_and_exit("EVP_DigestFinal_ex failed"); 118 | } 119 | 120 | EVP_PKEY_CTX* verify_pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); 121 | 122 | if (EVP_PKEY_verify_init(verify_pkey_ctx) <= 0) { 123 | error_and_exit("EVP_PKEY_verify_init failed"); 124 | } 125 | 126 | printf("MD type for ver_md_ctx (ver): %d\n", EVP_MD_type(EVP_MD_CTX_md(ver_md_ctx))); 127 | 128 | if (EVP_PKEY_CTX_set_rsa_padding(verify_pkey_ctx, RSA_PKCS1_PSS_PADDING) <= 0) { 129 | error_and_exit("EVP_PKEY_CTX_set_rsa_padding failed"); 130 | } 131 | 132 | printf("md_type: %d\n", EVP_MD_type(EVP_MD_CTX_md(ver_md_ctx))); 133 | /* 134 | * The following call will currently fail with the following error: 135 | * errno: 478150830, error:1C8000AE:Provider routines::digest not allowed 136 | */ 137 | if (EVP_PKEY_CTX_set_signature_md(verify_pkey_ctx, EVP_MD_CTX_md(ver_md_ctx)) <= 0) { 138 | error_and_exit("EVP_PKEY_CTX_set_signature_md failed"); 139 | } 140 | 141 | int verified = EVP_PKEY_verify(verify_pkey_ctx, sig, siglen, m, m_len); 142 | printf("verified signature: %s\n", verified == 1 ? "true" : "false"); 143 | if (verified != 1) { 144 | error_and_exit("EVP_PKEY_verify failed"); 145 | } 146 | } 147 | 148 | int main(int arc, char *argv[]) { 149 | printf("RSA Sign example\n"); 150 | 151 | EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA_PSS, NULL); 152 | const EVP_MD* md = EVP_get_digestbyname("SHA256"); 153 | 154 | EVP_PKEY* pkey = create_pkey(ctx, md); 155 | 156 | // So we have our key generated. We can now use it to sign 157 | unsigned char* sig; 158 | size_t siglen; 159 | sign(sig, siglen, pkey, md); 160 | 161 | // Now verify the signature. 162 | verify(sig, siglen, pkey, md); 163 | 164 | EVP_PKEY_CTX_free(ctx); 165 | exit(EXIT_SUCCESS); 166 | } 167 | -------------------------------------------------------------------------------- /s_client.sh: -------------------------------------------------------------------------------- 1 | OPENSSL_DIR=../openssl_build_master 2 | OPENSSL_BIN=${OPENSSL_DIR}/bin 3 | export LD_LIBRARY_PATH=${OPENSSL_DIR}/lib 4 | #${OPENSSL_BIN}/openssl s_client -key test.key -cert test.crt -pass "pass:test" -port 7777 5 | #${OPENSSL_BIN}/openssl s_client -tls1 -key test.key -cert test.crt -pass "pass:test" -port 7777 6 | 7 | ${OPENSSL_BIN}/openssl s_client -security_debug_verbose -debug -msg -key rsa_private.pem -cert rsa_cert.crt -tls1 -port 7777 8 | -------------------------------------------------------------------------------- /s_server.sh: -------------------------------------------------------------------------------- 1 | OPENSSL_DIR=../openssl_build_master 2 | OPENSSL_BIN=${OPENSSL_DIR}/bin 3 | export LD_LIBRARY_PATH=${OPENSSL_DIR}/lib 4 | #${OPENSSL_BIN}/openssl s_server -key test.key -cert test.crt -pass "pass:test" -port 7777 5 | 6 | ${OPENSSL_BIN}/openssl s_server -cipher "RSA@SECLEVEL=0" -tls1 -debug -msg -security_debug_verbose -provider legacy -provider default -key rsa_private.pem -cert rsa_cert.crt -port 7777 7 | -------------------------------------------------------------------------------- /secp256k1-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHQCAQEEIGTC4o5iP8+nQo7I1rQzrmoMtLVcxMLv9uBgJ55Su4scoAcGBSuBBAAK 3 | oUQDQgAE78k8HZXelb5mU5OCiKZ/Qdv8X1sC8nM4Gjl9JRbAYSGitXXSj0WrUF5K 4 | QDXytuhi5YmfzRJSqwri8elkgZHy4w== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /sign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int pass_cb(char *buf, int size, int rwflag, void *u) { 10 | int len; 11 | char *tmp; 12 | /* We'd probably do something else if 'rwflag' is 1 */ 13 | if (u) { 14 | tmp = "test"; 15 | len = strlen(tmp); 16 | memcpy(buf, tmp, len); 17 | return len; 18 | } else { 19 | return 0; 20 | } 21 | } 22 | 23 | EVP_PKEY* load_private_key(const char* file) { 24 | BIO *keybio; 25 | if ((keybio = BIO_new_file(file, "r")) == NULL) { 26 | ERR_print_errors_fp(stderr); 27 | exit(0); 28 | } 29 | EVP_PKEY* pkey = PEM_read_bio_PrivateKey(keybio, NULL, pass_cb, "test key"); 30 | if (pkey == NULL) { 31 | ERR_print_errors_fp(stderr); 32 | exit(0); 33 | } 34 | return pkey; 35 | } 36 | 37 | int main(int arc, char *argv[]) { 38 | ERR_load_crypto_strings(); 39 | OpenSSL_add_all_algorithms(); 40 | OPENSSL_no_config(); 41 | 42 | EVP_MD_CTX* mdctx = NULL; 43 | const EVP_MD* md = NULL; 44 | 45 | char msg[] = "Bajja\n"; 46 | unsigned char sig[1024]; 47 | md = EVP_get_digestbyname("SHA256"); 48 | unsigned int sig_len = 0; 49 | int i = 0;; 50 | EVP_PKEY* pkey = load_private_key("test.key"); 51 | 52 | // Create a Message Digest Context for the operations 53 | mdctx = EVP_MD_CTX_new(); 54 | ENGINE* engine = NULL; 55 | assert(mdctx != NULL); 56 | EVP_SignInit_ex(mdctx, md, engine); 57 | EVP_SignUpdate(mdctx, msg, strlen(msg)); 58 | EVP_SignFinal(mdctx, sig, &sig_len, pkey); 59 | 60 | printf("sig_len: %d\n", sig_len); 61 | 62 | EVP_MD_CTX_free(mdctx); 63 | printf("Digest is: "); 64 | for (i = 0; i < sig_len; i++) { 65 | printf("%02x", sig[i]); 66 | } 67 | printf("\n"); 68 | 69 | EVP_cleanup(); 70 | CRYPTO_cleanup_all_ex_data(); 71 | ERR_free_strings(); 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /socket.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int arc, char *argv[]) { 8 | char* get = "GET / HTTP/1.1\x0D\x0AHost: www.google.se\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A"; 9 | char buf[1024]; 10 | BIO* bio; 11 | 12 | ERR_load_crypto_strings(); 13 | OPENSSL_no_config(); 14 | 15 | bio = BIO_new_connect("www.google.com:80"); 16 | if (bio == NULL) { 17 | fprintf(stderr, "new_connect failed"); 18 | exit(1); 19 | } 20 | 21 | if (BIO_do_connect(bio) <= 0) { 22 | fprintf(stderr, "do_connect failed"); 23 | ERR_print_errors_fp(stderr); 24 | return -1; 25 | } 26 | 27 | BIO_write(bio, get, strlen(get)); 28 | 29 | for (;;) { 30 | int r = BIO_read(bio, buf, 1023); 31 | if (r <= 0) { 32 | break; 33 | } 34 | buf[r] = 0; 35 | fprintf(stdout, "%s", buf); 36 | } 37 | 38 | BIO_free_all(bio); 39 | 40 | /* if you omit the next, a small leak may be left when you make use of the 41 | * BIO (low level API) for e.g. base64 transformations 42 | */ 43 | CRYPTO_cleanup_all_ex_data(); 44 | 45 | /* Remove error strings */ 46 | ERR_free_strings(); 47 | 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/array-overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | //#include 3 | 4 | int main(int argc, char** argv) { 5 | char array[10]; 6 | //printf("argv[1]: %s\n", argv[1]); 7 | 8 | strcpy(array, argv[1]); 9 | 10 | //printf("array: %s\n", array); 11 | return 0; 12 | }; 13 | -------------------------------------------------------------------------------- /src/certificate/cert-body.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danbev/learning-openssl/2e288d1b318e6ae29d39facbb783bb9606fdadba/src/certificate/cert-body.bin -------------------------------------------------------------------------------- /src/certificate/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEFTCCAv2gAwIBAgIUaD3suf5l77d4TOqHqxf+Krx8jJYwDQYJKoZIhvcNAQEL 3 | BQAwgZkxCzAJBgNVBAYTAlNFMRIwEAYDVQQIDAlTdG9ja2hvbG0xEjAQBgNVBAcM 4 | CVN0b2NraG9sbTEQMA4GA1UECgwHUmVkIEhhdDESMBAGA1UECwwJbm9kZXNoaWZ0 5 | MRIwEAYDVQQDDAlsb2NhbGhvc3QxKDAmBgkqhkiG9w0BCQEWGWRhbmllbC5iZXZl 6 | bml1c0BnbWFpbC5jb20wHhcNMjEwODI3MDcwNTUwWhcNMjIwODI3MDcwNTUwWjCB 7 | mTELMAkGA1UEBhMCU0UxEjAQBgNVBAgMCVN0b2NraG9sbTESMBAGA1UEBwwJU3Rv 8 | Y2tob2xtMRAwDgYDVQQKDAdSZWQgSGF0MRIwEAYDVQQLDAlub2Rlc2hpZnQxEjAQ 9 | BgNVBAMMCWxvY2FsaG9zdDEoMCYGCSqGSIb3DQEJARYZZGFuaWVsLmJldmVuaXVz 10 | QGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMqvXixG 11 | ptPwm3RD9iUqpLoI7txLLoEHkl82V099R/CH+wCHONRDxvkZyZV384vyp8DnteYV 12 | IAyl51CK4HYSXaH6bk4IzUp75454LxP/I8QYbl3Iwt4lvmu71ZE5mk5rWPsXQ7Rm 13 | wyQ8ZuguSaG8k6eNFEEI7nNj6pGb9bFns1czY/E30zCbuoAmK/yaAf+O0fmJ3Swi 14 | xVAhas3yQwksQ9de/Hl8WtvCf/b+x5xplc8jWaq6AoULKgemKHF0evrfxdFCwVE3 15 | NoOM/Z7QfbPUwXyohpSFTAZARZGu4C605HmWL5QE2umMRqmVmwzzibEy7wnR/Oqa 16 | 6JhPFf2jHpqz/AUCAwEAAaNTMFEwHQYDVR0OBBYEFNxF2Rr5AZb4S6+/QvLmNqoj 17 | HBofMB8GA1UdIwQYMBaAFNxF2Rr5AZb4S6+/QvLmNqojHBofMA8GA1UdEwEB/wQF 18 | MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAwjKOX2wRuwOTXy5Erst6sLA/+B4H0N 19 | 1Yx4VVDgvV7ugLq2NvePpBAqnYXma42w0YU+O9GlGnAX474d3X4sKeXL6RN46895 20 | JQYMLLWz3GsuZbCSVcbioM4pn/aA04g+GvSDJFIFh8oEj6KD8FGiML9HpFgkwmX6 21 | HPrgihPJjhJukVqIQk0Ozrbc1U83OOfSjVbjx0KRq/27wU6OUTUmlIDxfqCXJ4PH 22 | GSsgGfMpS0LuckUEBOG+aPdBrEUQl3r+laiVKiab7nlRNvtj5LG7Nmy0zEHhjERp 23 | P1NeHp4yh1evukLg4NX+yMpucV/blzaLW+2VICTYQSdw1e3fLweA1PA= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /src/certificate/issuer-pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyq9eLEam0/CbdEP2JSqk 3 | ugju3EsugQeSXzZXT31H8If7AIc41EPG+RnJlXfzi/KnwOe15hUgDKXnUIrgdhJd 4 | ofpuTgjNSnvnjngvE/8jxBhuXcjC3iW+a7vVkTmaTmtY+xdDtGbDJDxm6C5JobyT 5 | p40UQQjuc2PqkZv1sWezVzNj8TfTMJu6gCYr/JoB/47R+YndLCLFUCFqzfJDCSxD 6 | 1178eXxa28J/9v7HnGmVzyNZqroChQsqB6YocXR6+t/F0ULBUTc2g4z9ntB9s9TB 7 | fKiGlIVMBkBFka7gLrTkeZYvlATa6YxGqZWbDPOJsTLvCdH86promE8V/aMemrP8 8 | BQIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /src/certificate/signature-decrypted.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danbev/learning-openssl/2e288d1b318e6ae29d39facbb783bb9606fdadba/src/certificate/signature-decrypted.bin -------------------------------------------------------------------------------- /src/certificate/signature.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danbev/learning-openssl/2e288d1b318e6ae29d39facbb783bb9606fdadba/src/certificate/signature.bin -------------------------------------------------------------------------------- /src/certificate/signature.txt: -------------------------------------------------------------------------------- 1 | 0c:23:28:e5:f6:c1:1b:b0:39:35:f2:e4:4a:ec:b7:ab:0b:03: 2 | ff:81:e0:7d:0d:d5:8c:78:55:50:e0:bd:5e:ee:80:ba:b6:36: 3 | f7:8f:a4:10:2a:9d:85:e6:6b:8d:b0:d1:85:3e:3b:d1:a5:1a: 4 | 70:17:e3:be:1d:dd:7e:2c:29:e5:cb:e9:13:78:eb:cf:79:25: 5 | 06:0c:2c:b5:b3:dc:6b:2e:65:b0:92:55:c6:e2:a0:ce:29:9f: 6 | f6:80:d3:88:3e:1a:f4:83:24:52:05:87:ca:04:8f:a2:83:f0: 7 | 51:a2:30:bf:47:a4:58:24:c2:65:fa:1c:fa:e0:8a:13:c9:8e: 8 | 12:6e:91:5a:88:42:4d:0e:ce:b6:dc:d5:4f:37:38:e7:d2:8d: 9 | 56:e3:c7:42:91:ab:fd:bb:c1:4e:8e:51:35:26:94:80:f1:7e: 10 | a0:97:27:83:c7:19:2b:20:19:f3:29:4b:42:ee:72:45:04:04: 11 | e1:be:68:f7:41:ac:45:10:97:7a:fe:95:a8:95:2a:26:9b:ee: 12 | 79:51:36:fb:63:e4:b1:bb:36:6c:b4:cc:41:e1:8c:44:69:3f: 13 | 53:5e:1e:9e:32:87:57:af:ba:42:e0:e0:d5:fe:c8:ca:6e:71: 14 | 5f:db:97:36:8b:5b:ed:95:20:24:d8:41:27:70:d5:ed:df:2f: 15 | 07:80:d4:f0 16 | -------------------------------------------------------------------------------- /ssl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int pass_cb(char *buf, int size, int rwflag, void *u) { 14 | int len; 15 | char *tmp; 16 | /* We'd probably do something else if 'rwflag' is 1 */ 17 | if (u) { 18 | printf("Get the password for \"%s\"\n", (char*)u); 19 | tmp = "test"; 20 | len = strlen(tmp); 21 | 22 | if (len <= 0) return 0; 23 | /* if too long, truncate */ 24 | if (len > size) len = size; 25 | memcpy(buf, tmp, len); 26 | return len; 27 | } else { 28 | return 0; 29 | } 30 | } 31 | 32 | /** 33 | * This example is pretty much the same as socket.c, the only thing that 34 | * changes is setting up and making the connection. 35 | */ 36 | int main(int arc, char *argv[]) { 37 | char* get = "GET / HTTP/1.1\x0D\x0AHost: www.google.se\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A"; 38 | char buf[1024]; 39 | BIO* bio; 40 | SSL_CTX* ctx; 41 | SSL* ssl; 42 | 43 | SSL_library_init(); 44 | ERR_load_crypto_strings(); 45 | OpenSSL_add_all_algorithms(); 46 | OPENSSL_no_config(); 47 | 48 | ctx = SSL_CTX_new(SSLv23_client_method()); 49 | if (ctx == NULL) { 50 | fprintf(stderr, "failed to create SSL_CTX\n"); 51 | ERR_print_errors_fp(stderr); 52 | return 1; 53 | } 54 | 55 | //X509_STORE* store = X509_STORE_new(); 56 | 57 | // context, filename, path 58 | //if (!SSL_CTX_load_verify_locations(ctx, "TrustStore.pem", NULL)) { 59 | if (!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx), "TrustStore.pem", NULL)) { 60 | fprintf(stderr, "failed to load trust store"); 61 | ERR_print_errors_fp(stderr); 62 | SSL_CTX_free(ctx); 63 | exit(0); 64 | } 65 | 66 | BIO *bp; 67 | if ((bp = BIO_new_file("test.crt", "r")) == NULL) { 68 | ERR_print_errors_fp(stderr); 69 | SSL_CTX_free(ctx); 70 | exit(0); 71 | } 72 | X509 *x509 = PEM_read_bio_X509(bp, NULL, pass_cb, NULL); 73 | //fprintf(stdout, "%p\n", x509); 74 | 75 | BIO *keybio; 76 | if ((keybio = BIO_new_file("test.key", "r")) == NULL) { 77 | ERR_print_errors_fp(stderr); 78 | SSL_CTX_free(ctx); 79 | exit(0); 80 | } 81 | EVP_PKEY *pkey; 82 | //pkey = PEM_read_bio_PrivateKey(keybio, NULL, pass_cb, "test key"); 83 | pkey = PEM_read_bio_PrivateKey(keybio, NULL, pass_cb, NULL); 84 | //fprintf(stdout, "%p\n", pkey); 85 | 86 | bio = BIO_new_ssl_connect(ctx); 87 | if (bio == NULL) { 88 | fprintf(stderr, "new_ssl_connect failed"); 89 | exit(1); 90 | } 91 | BIO_get_ssl(bio, &ssl); 92 | if (SSL_get_verify_result(ssl) != X509_V_OK) { 93 | fprintf(stderr, "verification failed"); 94 | ERR_print_errors_fp(stderr); 95 | return -1; 96 | } 97 | 98 | SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 99 | BIO_set_conn_hostname(bio, "www.google.com:443"); 100 | if (BIO_do_connect(bio) <= 0) { 101 | fprintf(stderr, "do_connect failed"); 102 | ERR_print_errors_fp(stderr); 103 | return -1; 104 | } 105 | 106 | BIO_write(bio, get, strlen(get)); 107 | 108 | for (;;) { 109 | int r = BIO_read(bio, buf, 1023); 110 | if (r <= 0) { 111 | break; 112 | } 113 | buf[r] = 0; 114 | fprintf(stdout, "%s", buf); 115 | } 116 | 117 | BIO_free_all(bio); 118 | 119 | SSL_CTX_free(ctx); 120 | 121 | /* if you omit the next, a small leak may be left when you make use of the 122 | * BIO (low level API) for e.g. base64 transformations 123 | */ 124 | CRYPTO_cleanup_all_ex_data(); 125 | 126 | /* Remove error strings */ 127 | ERR_free_strings(); 128 | 129 | return 0; 130 | } 131 | 132 | -------------------------------------------------------------------------------- /store.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void print_error() { 12 | char buf[256]; 13 | int err = ERR_get_error(); 14 | ERR_error_string_n(err, buf, sizeof(buf)); 15 | printf("errno: %d, %s\n", err, buf); 16 | } 17 | 18 | static int passwd_callback(char* buf, int size, int rwflag, void* u) { 19 | const char* passphrase = (char*) u; 20 | if (passphrase != NULL) { 21 | size_t buflen = (size_t) size; 22 | size_t len = strlen(passphrase); 23 | if (buflen < len) 24 | return -1; 25 | memcpy(buf, passphrase, len); 26 | return len; 27 | } 28 | return -1; 29 | } 30 | 31 | int main(int arc, char *argv[]) { 32 | printf("OpenSSL Store example\n"); 33 | OSSL_PROVIDER* provider; 34 | provider = OSSL_PROVIDER_load(NULL, "default"); 35 | const OSSL_PARAM do_nada[] = { 36 | OSSL_PARAM_END 37 | }; 38 | 39 | UI_METHOD* ui_method = UI_UTIL_wrap_read_pem_callback(passwd_callback, 0); 40 | OSSL_LIB_CTX* libctx = OSSL_LIB_CTX_new(); 41 | BIO* bio = BIO_new_file("./rsa_cert.crt", "r"); 42 | 43 | //OSSL_STORE_LOADER* store_loader = OSSL_STORE_LOADER_fetch("file", libctx, NULL); 44 | //OSSL_STORE_register_loader(store_loader); 45 | 46 | OSSL_STORE_CTX* ctx = OSSL_STORE_attach(bio, "file", libctx, NULL, 47 | ui_method, "pass", do_nada, NULL, NULL); 48 | 49 | print_error(); 50 | 51 | UI_destroy_method(ui_method); 52 | OSSL_PROVIDER_unload(provider); 53 | 54 | exit(EXIT_SUCCESS); 55 | } 56 | -------------------------------------------------------------------------------- /test.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICfzCCAegCCQCdA8SIl+QIdDANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMC 3 | U0UxEjAQBgNVBAgMCVN0b2NraG9sbTESMBAGA1UEBwwJU3RvY2tob2xtMRAwDgYD 4 | VQQKDAdUZXN0aW5nMQ0wCwYDVQQLDARUZXN0MQ0wCwYDVQQDDAR0ZXN0MRwwGgYJ 5 | KoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMB4XDTE3MDUwMjExNTc0NFoXDTE4MDUw 6 | MjExNTc0NFowgYMxCzAJBgNVBAYTAlNFMRIwEAYDVQQIDAlTdG9ja2hvbG0xEjAQ 7 | BgNVBAcMCVN0b2NraG9sbTEQMA4GA1UECgwHVGVzdGluZzENMAsGA1UECwwEVGVz 8 | dDENMAsGA1UEAwwEdGVzdDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTCB 9 | nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAz7pRaf3LCCH+O8hNSigR3YYTAwKV 10 | bs1uvKg81L5uDW5JThEWi/NotOb8m0FZQGTfx37cNuDeZAEho37Kem9c/in8GXsn 11 | Gg9Dn4NY0EneQ2dr9P3Bq+Ct+a3A5XZKz+jOuV9GTxWLHJjb4nzGqg7QSVeo1s8b 12 | sje2sAcZ88zmYPUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCnhLYkz7dtyl1j81tc 13 | joWpjJuYqprtCF5SjnCt4OyRMNsQlgJdXXlUqHf2D5oSneYcLsxJdPzUUTPFEAh9 14 | /MyBK4wgzpcF39OH3mZvW+SJIzz0x+jr0MqejmVihmdF+YZEn3wAO6C820degUbu 15 | IjWwqKmacFbamqAFxzZenmyQbA== 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /test.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: DES-EDE3-CBC,A8B152C32BF427D6 4 | 5 | ndKkwYJav/rs/TJwdHuzz2veg0z+Z8YErHH3rsam3dgCPa9OTJGzoti7SrUWrHdc 6 | Pfv8BWh3mbYeZGpn5e207yEOawXXK6NREhuEX95Yx0zFyebYBYwIQ0iI9OnGOjkJ 7 | 544LxfCbMi654mtYjDnNbYEIYD71otO5ODzS5f/R2Te1WWuvvOOh6qKIM8+3dgeu 8 | PR6ZdwLOJNdE+84EvpG5bozflJHcCjJG+N4I+h8wdx7uOio06nW06OcP43eiBMUw 9 | tf7Y4hYBNjBKlHMSuluLJ8zChoDh0SOpK+JMjHUdkfZjVxgJWv3T7Z2uOFEtK8GM 10 | TEDTRHieWHsEelFLzpRj6fdiszxV1mLyFT2TFCbvE3qsnpLVx34NNnKfieQgnfaE 11 | IYpWWQpd0kkcE+RCmhgK4ssChY9/gW4nhk01A2arQBS1z6PsfPJf+09F8qN/Pi0R 12 | jOAN6oR70i+4m62mzXrNBh9w51nIB7uULVCpJFcNrVYgMhr3MczBTaE7/D7j78bS 13 | uBJrr+p3MKhKwixi9+M3Qu4AVMSQlxik7kx/1B+M/nmMnZaOpdKAXXf5pmB3YsHd 14 | KP320myE8GOW3L2cJ2tPQOu4+1TGTCyHJdEEcnPEpCZjgevHFr11o1NLAIDx1m1g 15 | jnKtK9czGzosqqDDOEiy2tnMRhuL+dt+Bx0Zp+0NEH3vZYt6144e2fSEmFd2CTcz 16 | +slgF9A5dtP8o7ArVOqHCDGmOAWldSz/77qfVOwLtesccGrjW3WuBD7Y5gnkL3UX 17 | FLQc2kCE2sgm78yD0m+I4s42TfPV/7LgCK/CdlhRIrCjOEkyf6IvLQ== 18 | -----END RSA PRIVATE KEY----- 19 | -------------------------------------------------------------------------------- /wrong-tag.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static int passwd_callback(char* buf, int size, int rwflag, void* u) { 11 | const char* passphrase = (char*) u; 12 | if (passphrase != NULL) { 13 | size_t buflen = (size_t) size; 14 | size_t len = strlen(passphrase); 15 | if (buflen < len) 16 | return -1; 17 | memcpy(buf, passphrase, len); 18 | return len; 19 | } 20 | return -1; 21 | } 22 | 23 | int main(int arc, char *argv[]) { 24 | printf("asn1 wrong tag issue\n"); 25 | BIO *file_bio; 26 | BIO *key_bio; 27 | EVP_PKEY* pkey = NULL; 28 | 29 | file_bio = BIO_new_file("./dsa_private_encrypted_1025.pem", "r"); 30 | unsigned char key[4096]; 31 | int key_len = BIO_read(file_bio, key, sizeof(key)); 32 | printf("key_len: %d\n", key_len); 33 | printf("key: %s\n", key); 34 | 35 | key_bio = BIO_new_mem_buf(key, key_len); 36 | 37 | pkey = PEM_read_bio_PrivateKey(key_bio, NULL, passwd_callback, "secret"); 38 | 39 | BIO *bout; 40 | bout = BIO_new_fp(stdout, BIO_NOCLOSE); 41 | EVP_PKEY_print_private(bout, pkey, 0, NULL); 42 | printf("pkey id = %d\n", EVP_PKEY_id(pkey)); 43 | 44 | ERR_print_errors_fp(stdout); 45 | 46 | BIO_free(file_bio); 47 | EVP_PKEY_free(pkey); 48 | BIO_free(key_bio); 49 | 50 | exit(EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /wrong-tag2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void error_and_exit(const char* msg) { 13 | printf("%s\n", msg); 14 | char buf[256]; 15 | int err = ERR_get_error(); 16 | ERR_error_string_n(err, buf, sizeof(buf)); 17 | printf("errno: %d, %s\n", err, buf); 18 | exit(EXIT_FAILURE); 19 | } 20 | 21 | static int passwd_callback(char* buf, int size, int rwflag, void* u) { 22 | const char* passphrase = (char*) u; 23 | if (passphrase != NULL) { 24 | size_t buflen = (size_t) size; 25 | size_t len = strlen(passphrase); 26 | if (buflen < len) 27 | return -1; 28 | memcpy(buf, passphrase, len); 29 | return len; 30 | } 31 | return -1; 32 | } 33 | 34 | int main(int arc, char *argv[]) { 35 | printf("asn1 wrong tag issue (#2)\n"); 36 | BIO* file_bio; 37 | BIO* key_bio; 38 | EVP_PKEY* pkey = NULL; 39 | PKCS8_PRIV_KEY_INFO *p8inf = NULL; 40 | 41 | 42 | // Private key in pem format (DER in base64 format) 43 | file_bio = BIO_new_file("./rsa_private2.pem", "r"); 44 | 45 | unsigned char key[4096]; 46 | int key_len = BIO_read(file_bio, key, sizeof(key)); 47 | printf("key_len: %d\n", key_len); 48 | printf("key: %s\n", key); 49 | 50 | key_bio = BIO_new_mem_buf(key, key_len); 51 | pkey = PEM_read_bio_PrivateKey(key_bio, NULL, passwd_callback, ""); 52 | 53 | BIO_free(file_bio); 54 | 55 | key_bio = BIO_new_mem_buf(pkey, key_len); 56 | 57 | BIO* b = BIO_new(BIO_s_mem()); 58 | int err = i2d_PKCS8PrivateKey_bio(b, pkey, NULL, NULL, 0, NULL, NULL); 59 | 60 | BUF_MEM* bptr; 61 | BIO_get_mem_ptr(b, &bptr); 62 | 63 | p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(b, NULL); 64 | if (p8inf == NULL) { 65 | error_and_exit("check errors"); 66 | } 67 | 68 | int r = OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_DECODER, BIO_new_fp(stdout, BIO_NOCLOSE)); 69 | 70 | pkey = EVP_PKCS82PKEY(p8inf); 71 | if (pkey == NULL) { 72 | error_and_exit("check errors"); 73 | } 74 | 75 | BIO_free(key_bio); 76 | EVP_PKEY_free(pkey); 77 | error_and_exit("Finished. Check errors and exit"); 78 | 79 | exit(EXIT_SUCCESS); 80 | } 81 | -------------------------------------------------------------------------------- /x509.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int pass_cb(char* buf, int size, int rwflag, void* u) { 12 | int len; 13 | char* tmp; 14 | /* We'd probably do something else if 'rwflag' is 1 */ 15 | if (u) { 16 | printf("Get the password for \"%s\"\n", u); 17 | tmp = "test"; 18 | len = strlen(tmp); 19 | 20 | if (len <= 0) return 0; 21 | /* if too long, truncate */ 22 | if (len > size) len = size; 23 | memcpy(buf, tmp, len); 24 | return len; 25 | } 26 | return 0; 27 | } 28 | 29 | void error_and_exit(const char* msg) { 30 | printf("%s\n", msg); 31 | char buf[256]; 32 | int err = ERR_get_error(); 33 | ERR_error_string_n(err, buf, sizeof(buf)); 34 | printf("errno: %d, %s\n", err, buf); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | int SafeX509ExtPrint(const BIO* out, X509_EXTENSION* ext) { 39 | const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext); 40 | 41 | if (method != X509V3_EXT_get_nid(NID_subject_alt_name)) 42 | return -1; 43 | 44 | GENERAL_NAMES* names = (GENERAL_NAMES*)X509V3_EXT_d2i(ext); 45 | if (names == NULL) 46 | return -1; 47 | 48 | for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) { 49 | GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i); 50 | 51 | if (i != 0) 52 | BIO_write(out, ", ", 2); 53 | 54 | if (gen->type == GEN_DNS) { 55 | ASN1_IA5STRING* name = gen->d.dNSName; 56 | 57 | BIO_write(out, "DNS:", 4); 58 | BIO_write(out, name->data, name->length); 59 | } else { 60 | STACK_OF(CONF_VALUE)* nval = i2v_GENERAL_NAME( 61 | (X509V3_EXT_METHOD*)method, gen, NULL); 62 | if (nval == NULL) 63 | return -1; 64 | X509V3_EXT_val_prn(out, nval, 0, 0); 65 | sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); 66 | } 67 | } 68 | sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); 69 | 70 | return 1; 71 | } 72 | 73 | int main(int arc, char *argv[]) { 74 | printf("x509 example\n"); 75 | 76 | OSSL_PROVIDER* provider = OSSL_PROVIDER_load(NULL, "default"); 77 | SSL_CTX* ssl_ctx; 78 | BIO* bio; 79 | char buf[1024]; 80 | X509_EXTENSION* ext; 81 | 82 | if ((bio = BIO_new_file("agent1-cert.pem", "r")) == NULL) { 83 | ERR_print_errors_fp(stderr); 84 | SSL_CTX_free(ssl_ctx); 85 | exit(0); 86 | } 87 | 88 | X509* x509 = PEM_read_bio_X509(bio, NULL, pass_cb, NULL); 89 | int index = X509_get_ext_by_NID(x509, NID_info_access, -1); 90 | ext = X509_get_ext(x509, index); 91 | 92 | const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext); 93 | 94 | BIO* mbio = BIO_new(BIO_s_mem()); 95 | 96 | int ret = SafeX509ExtPrint(mbio, ext); 97 | ret = X509V3_EXT_print(mbio, ext, 0, 0); 98 | 99 | printf("Print info_access information:"); 100 | for (;;) { 101 | int r = BIO_read(mbio, buf, 1023); 102 | if (r <= 0) { 103 | break; 104 | } 105 | buf[r] = 0; 106 | printf("%s", buf); 107 | } 108 | 109 | //EVP_PKEY* pkey = X509_get_pubkey(x509); 110 | 111 | OSSL_PROVIDER_unload(provider); 112 | BIO_free_all(bio); 113 | exit(EXIT_SUCCESS); 114 | } 115 | --------------------------------------------------------------------------------