diff options
| -rw-r--r-- | openssl.c | 288 |
1 files changed, 240 insertions, 48 deletions
| @@ -28,12 +28,14 @@ | |||
| 28 | 28 | ||
| 29 | #include <limits.h> /* INT_MAX INT_MIN */ | 29 | #include <limits.h> /* INT_MAX INT_MIN */ |
| 30 | #include <string.h> /* memset(3) */ | 30 | #include <string.h> /* memset(3) */ |
| 31 | #include <math.h> /* fabs(3) floor(3) round(3) isfinite(3) */ | 31 | #include <math.h> /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ |
| 32 | #include <time.h> /* struct tm time_t strptime(3) */ | ||
| 32 | 33 | ||
| 33 | #include <openssl/err.h> | 34 | #include <openssl/err.h> |
| 34 | #include <openssl/bn.h> | 35 | #include <openssl/bn.h> |
| 35 | #include <openssl/x509.h> | 36 | #include <openssl/x509.h> |
| 36 | #include <openssl/x509v3.h> | 37 | #include <openssl/x509v3.h> |
| 38 | #include <openssl/evp.h> | ||
| 37 | 39 | ||
| 38 | #include <lua.h> | 40 | #include <lua.h> |
| 39 | #include <lualib.h> | 41 | #include <lualib.h> |
| @@ -48,6 +50,8 @@ | |||
| 48 | #define countof(a) (sizeof (a) / sizeof *(a)) | 50 | #define countof(a) (sizeof (a) / sizeof *(a)) |
| 49 | #define endof(a) (&(a)[countof(a)]) | 51 | #define endof(a) (&(a)[countof(a)]) |
| 50 | 52 | ||
| 53 | #define CLAMP(i, min, max) (((i) < (min))? (min) : ((i) > (max))? (max) : (i)) | ||
| 54 | |||
| 51 | 55 | ||
| 52 | static void *prepudata(lua_State *L, const char *tname, size_t size) { | 56 | static void *prepudata(lua_State *L, const char *tname, size_t size) { |
| 53 | void *p = memset(lua_newuserdata(L, size), 0, size); | 57 | void *p = memset(lua_newuserdata(L, size), 0, size); |
| @@ -124,10 +128,24 @@ static BIGNUM *bn_push(lua_State *L) { | |||
| 124 | } /* bn_push() */ | 128 | } /* bn_push() */ |
| 125 | 129 | ||
| 126 | 130 | ||
| 131 | #define checkbig_(a, b, c, ...) checkbig((a), (b), (c)) | ||
| 132 | #define checkbig(...) checkbig_(__VA_ARGS__, &(_Bool){ 0 }) | ||
| 133 | |||
| 134 | static BIGNUM *(checkbig)(lua_State *, int, _Bool *); | ||
| 135 | |||
| 127 | static int bn_new(lua_State *L) { | 136 | static int bn_new(lua_State *L) { |
| 128 | bn_push(L); | 137 | int i, n; |
| 129 | 138 | ||
| 130 | return 1; | 139 | if ((n = lua_gettop(L)) > 0) { |
| 140 | for (i = 1; i <= n; i++) | ||
| 141 | checkbig(L, i); | ||
| 142 | |||
| 143 | return n; | ||
| 144 | } else { | ||
| 145 | bn_push(L); | ||
| 146 | |||
| 147 | return 1; | ||
| 148 | } | ||
| 131 | } /* bn_new() */ | 149 | } /* bn_new() */ |
| 132 | 150 | ||
| 133 | 151 | ||
| @@ -204,7 +222,7 @@ static _Bool f2bn(BIGNUM **bn, double f) { | |||
| 204 | } /* f2bn() */ | 222 | } /* f2bn() */ |
| 205 | 223 | ||
| 206 | 224 | ||
| 207 | static BIGNUM *checkbig(lua_State *L, int index, _Bool *lvalue) { | 225 | static BIGNUM *(checkbig)(lua_State *L, int index, _Bool *lvalue) { |
| 208 | BIGNUM **bn; | 226 | BIGNUM **bn; |
| 209 | const char *dec; | 227 | const char *dec; |
| 210 | size_t len; | 228 | size_t len; |
| @@ -385,6 +403,15 @@ static int bn__pow(lua_State *L) { | |||
| 385 | } /* bn__pow() */ | 403 | } /* bn__pow() */ |
| 386 | 404 | ||
| 387 | 405 | ||
| 406 | static int bn__unm(lua_State *L) { | ||
| 407 | BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); | ||
| 408 | |||
| 409 | BN_set_negative(a, !BN_is_negative(a)); | ||
| 410 | |||
| 411 | return 1; | ||
| 412 | } /* bn__unm() */ | ||
| 413 | |||
| 414 | |||
| 388 | static int bn__eq(lua_State *L) { | 415 | static int bn__eq(lua_State *L) { |
| 389 | BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); | 416 | BIGNUM *a = checksimple(L, 1, BIGNUM_CLASS); |
| 390 | BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); | 417 | BIGNUM *b = checksimple(L, 2, BIGNUM_CLASS); |
| @@ -451,6 +478,7 @@ static const luaL_Reg bn_metatable[] = { | |||
| 451 | { "__div", &bn__div }, | 478 | { "__div", &bn__div }, |
| 452 | { "__mod", &bn__mod }, | 479 | { "__mod", &bn__mod }, |
| 453 | { "__pow", &bn__pow }, | 480 | { "__pow", &bn__pow }, |
| 481 | { "__unm", &bn__unm }, | ||
| 454 | { "__eq", &bn__eq }, | 482 | { "__eq", &bn__eq }, |
| 455 | { "__lt", &bn__lt }, | 483 | { "__lt", &bn__lt }, |
| 456 | { "__le", &bn__le }, | 484 | { "__le", &bn__le }, |
| @@ -622,12 +650,12 @@ static int xc_setVersion(lua_State *L) { | |||
| 622 | 650 | ||
| 623 | static int xc_getSerialNumber(lua_State *L) { | 651 | static int xc_getSerialNumber(lua_State *L) { |
| 624 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); | 652 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); |
| 625 | BIGNUM *srl = bn_push(L); | 653 | BIGNUM *serial = bn_push(L); |
| 626 | ASN1_INTEGER *num; | 654 | ASN1_INTEGER *i; |
| 627 | 655 | ||
| 628 | if ((num = X509_get_serialNumber(crt))) { | 656 | if ((i = X509_get_serialNumber(crt))) { |
| 629 | if (!ASN1_INTEGER_to_BN(num, srl)) | 657 | if (!ASN1_INTEGER_to_BN(i, serial)) |
| 630 | return throwssl(L, "x509.cert.getSerialNumber"); | 658 | return throwssl(L, "x509.cert:getSerialNumber"); |
| 631 | } | 659 | } |
| 632 | 660 | ||
| 633 | return 1; | 661 | return 1; |
| @@ -636,69 +664,233 @@ static int xc_getSerialNumber(lua_State *L) { | |||
| 636 | 664 | ||
| 637 | static int xc_setSerialNumber(lua_State *L) { | 665 | static int xc_setSerialNumber(lua_State *L) { |
| 638 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); | 666 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); |
| 639 | ASN1_INTEGER *srl = NULL; | 667 | ASN1_INTEGER *serial; |
| 640 | int ok; | ||
| 641 | |||
| 642 | luaL_checkany(L, 2); | ||
| 643 | |||
| 644 | if (lua_isstring(L, 2)) { | ||
| 645 | BIGNUM *num = NULL; | ||
| 646 | |||
| 647 | if (!BN_dec2bn(&num, lua_tostring(L, 2))) | ||
| 648 | goto error; | ||
| 649 | 668 | ||
| 650 | if (!(srl = ASN1_INTEGER_new()) || !(BN_to_ASN1_INTEGER(num, srl))) | 669 | if (!(serial = BN_to_ASN1_INTEGER(checkbig(L, 2), NULL))) |
| 651 | goto error; | 670 | goto error; |
| 652 | 671 | ||
| 653 | ok = X509_set_serialNumber(crt, srl); | 672 | if (!X509_set_serialNumber(crt, serial)) |
| 654 | ASN1_INTEGER_free(srl); | 673 | goto error; |
| 655 | 674 | ||
| 656 | if (!ok) | 675 | ASN1_INTEGER_free(serial); |
| 657 | goto error; | ||
| 658 | } else { | ||
| 659 | BIGNUM *num = checksimple(L, 2, BIGNUM_CLASS); | ||
| 660 | |||
| 661 | if (!(srl = ASN1_INTEGER_new()) || !(BN_to_ASN1_INTEGER(num, srl))) | ||
| 662 | goto error; | ||
| 663 | |||
| 664 | ok = X509_set_serialNumber(crt, srl); | ||
| 665 | ASN1_INTEGER_free(srl); | ||
| 666 | |||
| 667 | if (!ok) | ||
| 668 | goto error; | ||
| 669 | } | ||
| 670 | 676 | ||
| 671 | lua_pushboolean(L, 1); | 677 | lua_pushboolean(L, 1); |
| 672 | 678 | ||
| 673 | return 1; | 679 | return 1; |
| 674 | error: | 680 | error: |
| 675 | return throwssl(L, "x509.cert.setSerialNumber"); | 681 | ASN1_INTEGER_free(serial); |
| 682 | |||
| 683 | return throwssl(L, "x509.cert:setSerialNumber"); | ||
| 676 | } /* xc_setSerialNumber() */ | 684 | } /* xc_setSerialNumber() */ |
| 677 | 685 | ||
| 678 | 686 | ||
| 679 | #if 0 | ||
| 680 | static int xc_digest(lua_State *L) { | 687 | static int xc_digest(lua_State *L) { |
| 681 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); | 688 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); |
| 682 | const char *type = luaL_optstring(L, 2, "sha1"); | 689 | const char *type = luaL_optstring(L, 2, "sha1"); |
| 683 | const EVP_MD *dgst; | 690 | int format = luaL_checkoption(L, 3, "*s", (const char *[]){ "*s", "*x", "*n", NULL }); |
| 691 | const EVP_MD *ctx; | ||
| 684 | unsigned char md[EVP_MAX_MD_SIZE]; | 692 | unsigned char md[EVP_MAX_MD_SIZE]; |
| 685 | unsigned int len; | 693 | unsigned len; |
| 694 | |||
| 695 | lua_settop(L, 3); /* self, type, hex */ | ||
| 686 | 696 | ||
| 687 | if (!(dgst = EVP_getdigestbyname(type))) | 697 | if (!(ctx = EVP_get_digestbyname(type))) |
| 688 | return luaL_error(L, "x509.cert:digest: %s: invalid digest type", type); | 698 | return luaL_error(L, "x509.cert:digest: %s: invalid digest type", type); |
| 689 | 699 | ||
| 690 | X509_digest(crt, dgst, md, &len); | 700 | X509_digest(crt, ctx, md, &len); |
| 701 | |||
| 702 | switch (format) { | ||
| 703 | case 2: { | ||
| 704 | BIGNUM *bn = bn_push(L); | ||
| 705 | |||
| 706 | if (!BN_bin2bn(md, len, bn)) | ||
| 707 | return throwssl(L, "x509.cert:digest"); | ||
| 708 | |||
| 709 | break; | ||
| 710 | } | ||
| 711 | case 1: { | ||
| 712 | static const unsigned char x[16] = "0123456789abcdef"; | ||
| 713 | luaL_Buffer B; | ||
| 714 | |||
| 715 | luaL_buffinitsize(L, &B, 2 * len); | ||
| 716 | |||
| 717 | for (unsigned i = 0; i < len; i++) { | ||
| 718 | luaL_addchar(&B, x[0x0f & (md[i] >> 4)]); | ||
| 719 | luaL_addchar(&B, x[0x0f & (md[i] >> 0)]); | ||
| 720 | } | ||
| 721 | |||
| 722 | luaL_pushresult(&B); | ||
| 691 | 723 | ||
| 692 | lua_pushlstring(L, md, len); | 724 | break; |
| 725 | } | ||
| 726 | default: | ||
| 727 | lua_pushlstring(L, (const char *)md, len); | ||
| 728 | |||
| 729 | break; | ||
| 730 | } /* switch() */ | ||
| 693 | 731 | ||
| 694 | return 1; | 732 | return 1; |
| 695 | } /* xc_digest() */ | 733 | } /* xc_digest() */ |
| 696 | #endif | ||
| 697 | 734 | ||
| 698 | static int xc_lifetime(lua_State *L) { | 735 | |
| 736 | static _Bool isleap(int year) { | ||
| 737 | if (year >= 0) | ||
| 738 | return !(year % 4) && ((year % 100) || !(year % 400)); | ||
| 739 | else | ||
| 740 | return isleap(-(year + 1)); | ||
| 741 | } /* isleap() */ | ||
| 742 | |||
| 743 | |||
| 744 | static int yday(int year, int mon, int mday) { | ||
| 745 | static const int past[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; | ||
| 746 | int yday = past[CLAMP(mon, 0, 11)] + CLAMP(mday, 1, 31) - 1; | ||
| 747 | |||
| 748 | return yday + (isleap(year) && mon > 1); | ||
| 749 | } /* yday() */ | ||
| 750 | |||
| 751 | |||
| 752 | static int leaps(int year) { | ||
| 753 | if (year >= 0) | ||
| 754 | return (year / 400) + (year / 4) - (year / 100); | ||
| 755 | else | ||
| 756 | return -(leaps(-(year + 1)) + 1); | ||
| 757 | } /* leaps() */ | ||
| 758 | |||
| 759 | |||
| 760 | static _Bool scan(int *i, char **cp, int n, int signok) { | ||
| 761 | int sign = 1; | ||
| 762 | |||
| 763 | *i = 0; | ||
| 764 | |||
| 765 | if (signok) { | ||
| 766 | if (**cp == '-') { | ||
| 767 | sign = -1; | ||
| 768 | ++*cp; | ||
| 769 | } else if (**cp == '+') { | ||
| 770 | ++*cp; | ||
| 771 | } | ||
| 772 | } | ||
| 773 | |||
| 774 | while (n-- > 0) { | ||
| 775 | if (**cp < '0' || **cp > '9') | ||
| 776 | return 0; | ||
| 777 | |||
| 778 | *i *= 10; | ||
| 779 | *i += *(*cp)++ - '0'; | ||
| 780 | } | ||
| 781 | |||
| 782 | *i *= sign; | ||
| 783 | |||
| 784 | return 1; | ||
| 785 | } /* scan() */ | ||
| 786 | |||
| 787 | |||
| 788 | static double timeutc(ASN1_TIME *time) { | ||
| 789 | char buf[32] = "", *cp; | ||
| 790 | struct tm tm; | ||
| 791 | int gmtoff, year, i; | ||
| 792 | double ts; | ||
| 793 | |||
| 794 | if (!ASN1_TIME_check(time)) | ||
| 795 | return 0; | ||
| 796 | |||
| 797 | cp = strncpy(buf, (const char *)ASN1_STRING_data((ASN1_STRING *)time), sizeof buf - 1); | ||
| 798 | |||
| 799 | if (ASN1_STRING_type(time) == V_ASN1_GENERALIZEDTIME) { | ||
| 800 | if (!scan(&year, &cp, 4, 1)) | ||
| 801 | goto badfmt; | ||
| 802 | } else { | ||
| 803 | if (!scan(&year, &cp, 2, 0)) | ||
| 804 | goto badfmt; | ||
| 805 | year += (year < 50)? 2000 : 1999; | ||
| 806 | } | ||
| 807 | |||
| 808 | tm.tm_year = year - 1900; | ||
| 809 | |||
| 810 | if (!scan(&i, &cp, 2, 0)) | ||
| 811 | goto badfmt; | ||
| 812 | |||
| 813 | tm.tm_mon = CLAMP(i, 1, 12) - 1; | ||
| 814 | |||
| 815 | if (!scan(&i, &cp, 2, 0)) | ||
| 816 | goto badfmt; | ||
| 817 | |||
| 818 | tm.tm_mday = CLAMP(i, 1, 31); | ||
| 819 | |||
| 820 | tm.tm_yday = yday(year, tm.tm_mon, tm.tm_mday); | ||
| 821 | |||
| 822 | if (!scan(&i, &cp, 2, 0)) | ||
| 823 | goto badfmt; | ||
| 824 | |||
| 825 | tm.tm_hour = CLAMP(i, 0, 23); | ||
| 826 | |||
| 827 | if (!scan(&i, &cp, 2, 0)) | ||
| 828 | goto badfmt; | ||
| 829 | |||
| 830 | tm.tm_min = CLAMP(i, 0, 59); | ||
| 831 | |||
| 832 | if (*cp >= '0' && *cp <= '9') { | ||
| 833 | if (!scan(&i, &cp, 2, 0)) | ||
| 834 | goto badfmt; | ||
| 835 | |||
| 836 | tm.tm_sec = CLAMP(i, 0, 59); | ||
| 837 | } | ||
| 838 | |||
| 839 | if (*cp == '+' || *cp == '-') { | ||
| 840 | int sign = (*cp++ == '-')? -1 : 1; | ||
| 841 | int hh, mm; | ||
| 842 | |||
| 843 | if (!scan(&hh, &cp, 2, 0) || !scan(&mm, &cp, 2, 0)) | ||
| 844 | goto badfmt; | ||
| 845 | |||
| 846 | gmtoff = (CLAMP(hh, 0, 23) * 3600) | ||
| 847 | + (CLAMP(mm, 0, 59) * 60); | ||
| 848 | |||
| 849 | gmtoff *= sign; | ||
| 850 | } | ||
| 851 | |||
| 852 | ts = 86400.0 * 365.0 * (year - 1970); | ||
| 853 | ts += 86400.0 * (leaps(year - 1) - leaps(1969)); | ||
| 854 | ts += 86400 * tm.tm_yday; | ||
| 855 | ts += 3600 * tm.tm_hour; | ||
| 856 | ts += 60 * tm.tm_min; | ||
| 857 | ts += tm.tm_sec; | ||
| 858 | ts += (year < 1970)? gmtoff : -gmtoff; | ||
| 859 | |||
| 860 | return ts; | ||
| 861 | badfmt: | ||
| 862 | return INFINITY; | ||
| 863 | } /* timeutc() */ | ||
| 864 | |||
| 865 | |||
| 866 | static int xc_getLifetime(lua_State *L) { | ||
| 699 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); | 867 | X509 *crt = checksimple(L, 1, X509_CERT_CLASS); |
| 700 | return 0; | 868 | double begin = INFINITY, end = INFINITY; |
| 701 | } /* xc_lifetime() */ | 869 | ASN1_TIME *time; |
| 870 | |||
| 871 | if ((time = X509_get_notBefore(crt))) | ||
| 872 | begin = timeutc(time); | ||
| 873 | |||
| 874 | if ((time = X509_get_notAfter(crt))) | ||
| 875 | end = timeutc(time); | ||
| 876 | |||
| 877 | if (isfinite(begin)) | ||
| 878 | lua_pushnumber(L, begin); | ||
| 879 | else | ||
| 880 | lua_pushnil(L); | ||
| 881 | |||
| 882 | if (isfinite(end)) | ||
| 883 | lua_pushnumber(L, end); | ||
| 884 | else | ||
| 885 | lua_pushnil(L); | ||
| 886 | |||
| 887 | if (isfinite(begin) && isfinite(end) && begin <= end) | ||
| 888 | lua_pushnumber(L, fabs(end - begin)); | ||
| 889 | else | ||
| 890 | lua_pushnumber(L, 0.0); | ||
| 891 | |||
| 892 | return 3; | ||
| 893 | } /* xc_getLifetime() */ | ||
| 702 | 894 | ||
| 703 | 895 | ||
| 704 | static int xc_issuer(lua_State *L) { | 896 | static int xc_issuer(lua_State *L) { |
