err with multiple TLS sites but one OCSP?
Sooo.. Pretty sure mlucas has uncovered a problem with the ocsp interface. Basically I didn't attach it to the keypair, (yes Joel, I think you told me so) so it only works with the master keypair.. OK, but the problem is that it also returns the staple for other keypairs which is wrong. This attaches the ocsp staple to the keypair, rather than the config. It does not yet add a way to change it for keypairs other than the master - that will require an API change - but with this change it should not return an incorrect ocsp staple for the non primary keypair. I'll deal with the API change separately after pestering joel about it a bit. ok? Index: tls_config.c === RCS file: /cvs/src/lib/libtls/tls_config.c,v retrieving revision 1.34 diff -u -p -u -p -r1.34 tls_config.c --- tls_config.c24 Jan 2017 01:48:05 - 1.34 +++ tls_config.c28 Jan 2017 21:40:14 - @@ -101,6 +101,26 @@ tls_keypair_set_key_mem(struct tls_keypa return set_mem(&keypair->key_mem, &keypair->key_len, key, len); } +static int +tls_keypair_set_ocsp_staple_file(struct tls_keypair *keypair, +struct tls_error *error, const char *ocsp_file) +{ + if (keypair->ocsp_staple != NULL) + explicit_bzero(keypair->ocsp_staple, keypair->ocsp_staple_len); + return tls_config_load_file(error, "ocsp", ocsp_file, + &keypair->ocsp_staple, &keypair->ocsp_staple_len); +} + +static int +tls_keypair_set_ocsp_staple_mem(struct tls_keypair *keypair, +const uint8_t *staple, size_t len) +{ + if (keypair->ocsp_staple != NULL) + explicit_bzero(keypair->ocsp_staple, keypair->ocsp_staple_len); + return set_mem(&keypair->ocsp_staple, &keypair->ocsp_staple_len, staple, + len); +} + static void tls_keypair_clear(struct tls_keypair *keypair) { @@ -241,7 +261,6 @@ tls_config_free(struct tls_config *confi free((char *)config->ca_mem); free((char *)config->ca_path); free((char *)config->ciphers); - free(config->ocsp_staple); free(config); } @@ -664,14 +683,14 @@ tls_config_verify_client_optional(struct int tls_config_set_ocsp_staple_file(struct tls_config *config, const char *staple_file) { - return tls_config_load_file(&config->error, "OCSP", staple_file, - &config->ocsp_staple, &config->ocsp_staple_len); + return tls_keypair_set_ocsp_staple_file(config->keypair, &config->error, + staple_file); } int tls_config_set_ocsp_staple_mem(struct tls_config *config, char *staple, size_t len) { - return set_mem(&config->ocsp_staple, &config->ocsp_staple_len, staple, len); + return tls_keypair_set_ocsp_staple_mem(config->keypair, staple, len); } int Index: tls_internal.h === RCS file: /cvs/src/lib/libtls/tls_internal.h,v retrieving revision 1.52 diff -u -p -u -p -r1.52 tls_internal.h --- tls_internal.h 26 Jan 2017 12:56:37 - 1.52 +++ tls_internal.h 28 Jan 2017 21:07:25 - @@ -51,6 +51,8 @@ struct tls_keypair { size_t cert_len; char *key_mem; size_t key_len; + char *ocsp_staple; + size_t ocsp_staple_len; }; #define TLS_MIN_SESSION_TIMEOUT (4) @@ -83,8 +85,6 @@ struct tls_config { int ecdhecurve; struct tls_keypair *keypair; int ocsp_require_stapling; - char *ocsp_staple; - size_t ocsp_staple_len; uint32_t protocols; unsigned char session_id[TLS_MAX_SESSION_ID_LENGTH]; int session_lifetime; Index: tls_ocsp.c === RCS file: /cvs/src/lib/libtls/tls_ocsp.c,v retrieving revision 1.10 diff -u -p -u -p -r1.10 tls_ocsp.c --- tls_ocsp.c 27 Jan 2017 07:03:27 - 1.10 +++ tls_ocsp.c 28 Jan 2017 21:42:22 - @@ -332,17 +332,19 @@ tls_ocsp_stapling_cb(SSL *ssl, void *arg if ((ctx = SSL_get_app_data(ssl)) == NULL) goto err; - if (ctx->config->ocsp_staple == NULL || - ctx->config->ocsp_staple_len == 0) + if (ctx->config->keypair->ocsp_staple == NULL || + ctx->config->keypair->ocsp_staple == NULL || + ctx->config->keypair->ocsp_staple_len == 0) return SSL_TLSEXT_ERR_NOACK; - if ((ocsp_staple = malloc(ctx->config->ocsp_staple_len)) == NULL) + if ((ocsp_staple = malloc(ctx->config->keypair->ocsp_staple_len)) == + NULL) goto err; - memcpy(ocsp_staple, ctx->config->ocsp_staple, - ctx->config->ocsp_staple_len); + memcpy(ocsp_staple, ctx->config->keypair->ocsp_staple, + ctx->config->keypair->ocsp_staple_len); if (SSL_set_tlsext_status_ocsp_resp(ctx->ssl_conn, ocsp_staple, - ctx->config->ocsp_staple_len) != 1) + ctx->config->keypair->ocsp_staple_len) != 1) goto err;
Re: err with multiple TLS sites but one OCSP?
On Fri, Jan 27, 2017 at 09:53:25PM +, Bob Beck wrote: >On Fri, Jan 27, 2017 at 14:12 Michael W. Lucas > Or a misconfiguration. ? show configs Configs follow. # cat /etc/httpd.conf include "/etc/sites/www3.conf" include "/etc/sites/www4.conf" www3.conf: server "www3.mwlucas.org" { listen on * port 80 block return 302 "https://$SERVER_NAME$REQUEST_URI"; } server "www3.mwlucas.org" { alias tarpit.mwlucas.org listen on * tls port 443 hsts # TLS certificate and key files created with acme-client(1) tls certificate "/etc/ssl/acme/www3/www3.fullchain.pem" tls key "/etc/ssl/acme/www3/www3.key" tls ocsp "/etc/ssl/acme/www3/www3.der" tcp nodelay location "/.well-known/acme-challenge/*" { root "/acme" root strip 2 } } www4: server "www4.mwlucas.org" { alias bill.mwlucas.org alias auction.mwlucas.org listen on * port 80 location "/.well-known/acme-challenge/*" { root "/acme" root strip 2 } block return 301 "https://$DOCUMENT_URI"; } server "www4.mwlucas.org" { alias bill.mwlucas.org alias auction.mwlucas.org root "/www4" listen on * tls port 443 hsts # TLS certificate and key files created with acme-client(1) tls certificate "/etc/ssl/acme/www4/www4.fullchain.pem" tls key "/etc/ssl/acme/www4/www4.key" # tls ocsp "/etc/ssl/acme/www4/www4.der" tcp nodelay location "/.well-known/acme-challenge/*" { root "/acme" root strip 2 } } -- Michael W. LucasTwitter @mwlauthor nonfiction: https://www.michaelwlucas.com/ fiction: https://www.michaelwarrenlucas.com/ blog: http://blather.michaelwlucas.com/
Re: err with multiple TLS sites but one OCSP?
On Fri, Jan 27, 2017 at 15:23 Stuart Henderson wrote: > On 2017/01/27 22:09, Bob Beck wrote: > > > I think you have more issues than ocsp. if thats the same host you can't > > > have two different tls certs on the same ip. and you have them both on > > > *443 > > > > > > try using a separate ip for each > > > > Wasn't SNI support added to httpd already? > > hmmm. right. but i bet itll work with explicit separate ip's. stapling on > the other hand will be per config. so thats probably whats fighting. > separate ip would confirm that. > im tired. ill look at it tomorrow unless someone else does > > >
Re: err with multiple TLS sites but one OCSP?
On 2017/01/27 22:09, Bob Beck wrote: > I think you have more issues than ocsp. if thats the same host you can't > have two different tls certs on the same ip. and you have them both on > *443 > > try using a separate ip for each Wasn't SNI support added to httpd already?
Re: err with multiple TLS sites but one OCSP?
I think you have more issues than ocsp. if thats the same host you can't have two different tls certs on the same ip. and you have them both on *443 try using a separate ip for each On Fri, Jan 27, 2017 at 15:03 Michael W. Lucas wrote: > On Fri, Jan 27, 2017 at 09:53:25PM +, Bob Beck wrote: > > >On Fri, Jan 27, 2017 at 14:12 Michael W. Lucas > > > Or a misconfiguration. Â show configs > > > > > > Configs follow. > > > > # cat /etc/httpd.conf > > include "/etc/sites/www3.conf" > > include "/etc/sites/www4.conf" > > > > www3.conf: > > > > server "www3.mwlucas.org" { > >listen on * port 80 > >block return 302 "https://$SERVER_NAME$REQUEST_URI"; > > } > > > > > > server "www3.mwlucas.org" { > > alias tarpit.mwlucas.org > > listen on * tls port 443 > > hsts > > # TLS certificate and key files created with acme-client(1) > > tls certificate "/etc/ssl/acme/www3/www3.fullchain.pem" > > tls key "/etc/ssl/acme/www3/www3.key" > > tls ocsp "/etc/ssl/acme/www3/www3.der" > > tcp nodelay > > > >location "/.well-known/acme-challenge/*" { > >root "/acme" > >root strip 2 > >} > > } > > > > > > www4: > > > > server "www4.mwlucas.org" { > > alias bill.mwlucas.org > > alias auction.mwlucas.org > > listen on * port 80 > > > >location "/.well-known/acme-challenge/*" { > >root "/acme" > >root strip 2 > >} > > > > > > block return 301 "https://$DOCUMENT_URI"; > > } > > > > server "www4.mwlucas.org" { > > alias bill.mwlucas.org > > alias auction.mwlucas.org > > root "/www4" > > listen on * tls port 443 > > hsts > > # TLS certificate and key files created with acme-client(1) > > tls certificate "/etc/ssl/acme/www4/www4.fullchain.pem" > > tls key "/etc/ssl/acme/www4/www4.key" > > # tls ocsp "/etc/ssl/acme/www4/www4.der" > > tcp nodelay > >location "/.well-known/acme-challenge/*" { > >root "/acme" > >root strip 2 > >} > > > > } > > > > > > > > > > -- > > Michael W. LucasTwitter @mwlauthor > > nonfiction: https://www.michaelwlucas.com/ > > fiction: https://www.michaelwarrenlucas.com/ > > blog: http://blather.michaelwlucas.com/ > >
Re: err with multiple TLS sites but one OCSP?
On Fri, Jan 27, 2017 at 14:12 Michael W. Lucas wrote: > On Fri, Jan 27, 2017 at 02:50:29PM -0500, Michael W. Lucas wrote: > > > On Fri, Jan 27, 2017 at 06:49:06PM +, Stuart Henderson wrote: > > > > That looks like a web server bug, it shouldn't return a staple > > > Or a misconfiguration. show configs > > > > > in that case. What software are you using for that? > > > > > > > > > > > > OpenBSD httpd, of course. amd64 snapshot downloaded yesterday from > > > ftp3.usa.openbsd.org. > > > > To be clear, that's a "How the hell could I forget to include that?" > > facepalm, not anything about Stuart asking the question... > > > > -- > > Michael W. LucasTwitter @mwlauthor > > nonfiction: https://www.michaelwlucas.com/ > > fiction: https://www.michaelwarrenlucas.com/ > > blog: http://blather.michaelwlucas.com/ > > > >
Re: err with multiple TLS sites but one OCSP?
On Fri, Jan 27, 2017 at 02:50:29PM -0500, Michael W. Lucas wrote: > On Fri, Jan 27, 2017 at 06:49:06PM +, Stuart Henderson wrote: > > That looks like a web server bug, it shouldn't return a staple > > in that case. What software are you using for that? > > > > OpenBSD httpd, of course. amd64 snapshot downloaded yesterday from > ftp3.usa.openbsd.org. To be clear, that's a "How the hell could I forget to include that?" facepalm, not anything about Stuart asking the question... -- Michael W. LucasTwitter @mwlauthor nonfiction: https://www.michaelwlucas.com/ fiction: https://www.michaelwarrenlucas.com/ blog: http://blather.michaelwlucas.com/
Re: err with multiple TLS sites but one OCSP?
On Fri, Jan 27, 2017 at 06:49:06PM +, Stuart Henderson wrote: > That looks like a web server bug, it shouldn't return a staple > in that case. What software are you using for that? OpenBSD httpd, of course. amd64 snapshot downloaded yesterday from ftp3.usa.openbsd.org. ==ml -- Michael W. LucasTwitter @mwlauthor nonfiction: https://www.michaelwlucas.com/ fiction: https://www.michaelwarrenlucas.com/ blog: http://blather.michaelwlucas.com/
Re: err with multiple TLS sites but one OCSP?
On 2017/01/27 13:10, Michael W. Lucas wrote: > Hi, > > Not sure if this is an expected part of OCSP or a bug. > > I've configured two TLS sites on one host, one with OCSP stapling > (www3.mwlucas.org) and one without (www4.mwlucas.org). The OCSP site > works fine, but the non-OCSP site generates an err. > > It *appears* that queries to the non-OCSP site return the OCSP site's > OCSP cert. > > Following please find openssl queries on both. Feel free to check the > sites yourself, I'm FAR from a TLS guru. That looks like a web server bug, it shouldn't return a staple in that case. What software are you using for that? > # openssl s_client -connect www4.mwlucas.org:443 -status -servername > www4.mwlucas.org > ... > verify return:1 > OCSP response: > == > OCSP Response Data: > OCSP Response Status: successful (0x0) > Response Type: Basic OCSP Response > Version: 1 (0x0) > Responder Id: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 > Produced At: Jan 26 23:02:00 2017 GMT > Responses: > Certificate ID: > Hash Algorithm: sha1 > Issuer Name Hash: 7EE66AE7729AB3FCF8A220646C16A12D6071085D > Issuer Key Hash: A84A6A63047DDDBAE6D139B7A64565EFF3A8ECA1 > Serial Number: 032CBDA721856F117CC7D57A72BBFA77B578 > Cert Status: good > This Update: Jan 26 23:00:00 2017 GMT > Next Update: Feb 2 23:00:00 2017 GMT > > Signature Algorithm: sha256WithRSAEncryption > 6a:1e:f1:44:8c:a9:a6:7e:40:25:3a:f7:50:e9:43:42:0f:74: > 9b:dc:ee:56:a3:47:0b:ce:73:88:ee:f0:84:fc:b0:25:5b:3d: > 67:d0:66:20:c7:60:7c:ee:26:91:72:4e:d0:f2:67:5a:e3:c1: > 06:57:31:47:29:1a:55:19:48:e7:e6:32:0b:18:d9:33:9d:55: > d7:36:38:f1:96:57:bc:5d:89:82:31:bb:4e:12:0c:5c:ab:1a: > f6:1d:a1:48:be:1c:1d:3b:52:a0:60:2f:1d:f9:3c:48:cd:df: > a6:5e:b5:79:0c:b9:ed:d5:61:29:53:ee:83:5f:89:af:35:27: > d6:94:05:f5:fb:d1:a8:4d:26:8d:8b:cf:e9:db:53:ad:e6:47: > a7:db:91:9e:9d:a1:b2:2c:1e:d9:98:c5:af:5c:12:d1:04:5a: > 82:be:8d:80:1f:38:c2:5d:b1:6f:99:e1:ca:53:71:1c:85:0d: > 3e:f3:14:bc:3b:c9:c0:dd:6b:ec:59:d4:54:dc:fb:9c:da:72: > 91:45:61:55:69:e9:75:51:8f:e2:82:6a:dd:ec:bc:bd:3c:2c: > 92:43:f7:d9:65:1d:60:14:91:e0:b0:2b:46:25:49:35:74:99: > 71:a3:c0:d0:91:66:29:7e:01:1b:35:f1:2e:40:dc:f3:4d:98: > 69:40:6f:46 > > > # openssl s_client -connect www3.mwlucas.org:443 -status -servername > www3.mwlucas.org > CONNECTED(0003) > depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 > verify return:1 > depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 > verify return:1 > depth=0 CN = www3.mwlucas.org > verify return:1 > OCSP response: > == > OCSP Response Data: > OCSP Response Status: successful (0x0) > Response Type: Basic OCSP Response > Version: 1 (0x0) > Responder Id: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 > Produced At: Jan 26 23:02:00 2017 GMT > Responses: > Certificate ID: > Hash Algorithm: sha1 > Issuer Name Hash: 7EE66AE7729AB3FCF8A220646C16A12D6071085D > Issuer Key Hash: A84A6A63047DDDBAE6D139B7A64565EFF3A8ECA1 > Serial Number: 032CBDA721856F117CC7D57A72BBFA77B578 > Cert Status: good > This Update: Jan 26 23:00:00 2017 GMT > Next Update: Feb 2 23:00:00 2017 GMT > > Signature Algorithm: sha256WithRSAEncryption > 6a:1e:f1:44:8c:a9:a6:7e:40:25:3a:f7:50:e9:43:42:0f:74: > 9b:dc:ee:56:a3:47:0b:ce:73:88:ee:f0:84:fc:b0:25:5b:3d: > 67:d0:66:20:c7:60:7c:ee:26:91:72:4e:d0:f2:67:5a:e3:c1: > 06:57:31:47:29:1a:55:19:48:e7:e6:32:0b:18:d9:33:9d:55: > d7:36:38:f1:96:57:bc:5d:89:82:31:bb:4e:12:0c:5c:ab:1a: > f6:1d:a1:48:be:1c:1d:3b:52:a0:60:2f:1d:f9:3c:48:cd:df: > a6:5e:b5:79:0c:b9:ed:d5:61:29:53:ee:83:5f:89:af:35:27: > d6:94:05:f5:fb:d1:a8:4d:26:8d:8b:cf:e9:db:53:ad:e6:47: > a7:db:91:9e:9d:a1:b2:2c:1e:d9:98:c5:af:5c:12:d1:04:5a: > 82:be:8d:80:1f:38:c2:5d:b1:6f:99:e1:ca:53:71:1c:85:0d: > 3e:f3:14:bc:3b:c9:c0:dd:6b:ec:59:d4:54:dc:fb:9c:da:72: > 91:45:61:55:69:e9:75:51:8f:e2:82:6a:dd:ec:bc:bd:3c:2c: > 92:43:f7:d9:65:1d:60:14:91:e0:b0:2b:46:25:49:35:74:99: > 71:a3:c0:d0:91:66:29:7e:01:1b:35:f1:2e:40:dc:f3:4d:98: > 69:40:6f:46 > == > ... > > ==ml > > > -- > Michael W. LucasTwitter @mwlauthor > nonfiction: https://www.michaelwlucas.com/ > fiction: https://www.michaelwarrenlucas.com/ > blog: http://blather.michaelwlucas.com/ >
err with multiple TLS sites but one OCSP?
Hi, Not sure if this is an expected part of OCSP or a bug. I've configured two TLS sites on one host, one with OCSP stapling (www3.mwlucas.org) and one without (www4.mwlucas.org). The OCSP site works fine, but the non-OCSP site generates an err. It *appears* that queries to the non-OCSP site return the OCSP site's OCSP cert. Following please find openssl queries on both. Feel free to check the sites yourself, I'm FAR from a TLS guru. # openssl s_client -connect www4.mwlucas.org:443 -status -servername www4.mwlucas.org ... verify return:1 OCSP response: == OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 Produced At: Jan 26 23:02:00 2017 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7EE66AE7729AB3FCF8A220646C16A12D6071085D Issuer Key Hash: A84A6A63047DDDBAE6D139B7A64565EFF3A8ECA1 Serial Number: 032CBDA721856F117CC7D57A72BBFA77B578 Cert Status: good This Update: Jan 26 23:00:00 2017 GMT Next Update: Feb 2 23:00:00 2017 GMT Signature Algorithm: sha256WithRSAEncryption 6a:1e:f1:44:8c:a9:a6:7e:40:25:3a:f7:50:e9:43:42:0f:74: 9b:dc:ee:56:a3:47:0b:ce:73:88:ee:f0:84:fc:b0:25:5b:3d: 67:d0:66:20:c7:60:7c:ee:26:91:72:4e:d0:f2:67:5a:e3:c1: 06:57:31:47:29:1a:55:19:48:e7:e6:32:0b:18:d9:33:9d:55: d7:36:38:f1:96:57:bc:5d:89:82:31:bb:4e:12:0c:5c:ab:1a: f6:1d:a1:48:be:1c:1d:3b:52:a0:60:2f:1d:f9:3c:48:cd:df: a6:5e:b5:79:0c:b9:ed:d5:61:29:53:ee:83:5f:89:af:35:27: d6:94:05:f5:fb:d1:a8:4d:26:8d:8b:cf:e9:db:53:ad:e6:47: a7:db:91:9e:9d:a1:b2:2c:1e:d9:98:c5:af:5c:12:d1:04:5a: 82:be:8d:80:1f:38:c2:5d:b1:6f:99:e1:ca:53:71:1c:85:0d: 3e:f3:14:bc:3b:c9:c0:dd:6b:ec:59:d4:54:dc:fb:9c:da:72: 91:45:61:55:69:e9:75:51:8f:e2:82:6a:dd:ec:bc:bd:3c:2c: 92:43:f7:d9:65:1d:60:14:91:e0:b0:2b:46:25:49:35:74:99: 71:a3:c0:d0:91:66:29:7e:01:1b:35:f1:2e:40:dc:f3:4d:98: 69:40:6f:46 # openssl s_client -connect www3.mwlucas.org:443 -status -servername www3.mwlucas.org CONNECTED(0003) depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 verify return:1 depth=0 CN = www3.mwlucas.org verify return:1 OCSP response: == OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 Produced At: Jan 26 23:02:00 2017 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 7EE66AE7729AB3FCF8A220646C16A12D6071085D Issuer Key Hash: A84A6A63047DDDBAE6D139B7A64565EFF3A8ECA1 Serial Number: 032CBDA721856F117CC7D57A72BBFA77B578 Cert Status: good This Update: Jan 26 23:00:00 2017 GMT Next Update: Feb 2 23:00:00 2017 GMT Signature Algorithm: sha256WithRSAEncryption 6a:1e:f1:44:8c:a9:a6:7e:40:25:3a:f7:50:e9:43:42:0f:74: 9b:dc:ee:56:a3:47:0b:ce:73:88:ee:f0:84:fc:b0:25:5b:3d: 67:d0:66:20:c7:60:7c:ee:26:91:72:4e:d0:f2:67:5a:e3:c1: 06:57:31:47:29:1a:55:19:48:e7:e6:32:0b:18:d9:33:9d:55: d7:36:38:f1:96:57:bc:5d:89:82:31:bb:4e:12:0c:5c:ab:1a: f6:1d:a1:48:be:1c:1d:3b:52:a0:60:2f:1d:f9:3c:48:cd:df: a6:5e:b5:79:0c:b9:ed:d5:61:29:53:ee:83:5f:89:af:35:27: d6:94:05:f5:fb:d1:a8:4d:26:8d:8b:cf:e9:db:53:ad:e6:47: a7:db:91:9e:9d:a1:b2:2c:1e:d9:98:c5:af:5c:12:d1:04:5a: 82:be:8d:80:1f:38:c2:5d:b1:6f:99:e1:ca:53:71:1c:85:0d: 3e:f3:14:bc:3b:c9:c0:dd:6b:ec:59:d4:54:dc:fb:9c:da:72: 91:45:61:55:69:e9:75:51:8f:e2:82:6a:dd:ec:bc:bd:3c:2c: 92:43:f7:d9:65:1d:60:14:91:e0:b0:2b:46:25:49:35:74:99: 71:a3:c0:d0:91:66:29:7e:01:1b:35:f1:2e:40:dc:f3:4d:98: 69:40:6f:46 == ... ==ml -- Michael W. LucasTwitter @mwlauthor nonfiction: https://www.michaelwlucas.com/ fiction: https://www.michaelwarrenlucas.com/ blog: http://blather.michaelwlucas.com/