diff options
Diffstat (limited to 'src/microhttpd/digestauth.c')
-rw-r--r-- | src/microhttpd/digestauth.c | 207 |
1 files changed, 105 insertions, 102 deletions
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c index 9c3fe8c5..4cc7f61b 100644 --- a/src/microhttpd/digestauth.c +++ b/src/microhttpd/digestauth.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of libmicrohttpd | 2 | This file is part of libmicrohttpd |
3 | Copyright (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff | 3 | Copyright (C) 2010, 2011, 2012, 2015 Daniel Pittman and Christian Grothoff |
4 | 4 | ||
5 | This library is free software; you can redistribute it and/or | 5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public | 6 | modify it under the terms of the GNU Lesser General Public |
@@ -472,8 +472,8 @@ test_header (struct MHD_Connection *connection, | |||
472 | * | 472 | * |
473 | * @param connection connections with headers to compare against | 473 | * @param connection connections with headers to compare against |
474 | * @param args argument URI string (after "?" in URI) | 474 | * @param args argument URI string (after "?" in URI) |
475 | * @return MHD_YES if the arguments match, | 475 | * @return #MHD_YES if the arguments match, |
476 | * MHD_NO if not | 476 | * #MHD_NO if not |
477 | */ | 477 | */ |
478 | static int | 478 | static int |
479 | check_argument_match (struct MHD_Connection *connection, | 479 | check_argument_match (struct MHD_Connection *connection, |
@@ -632,10 +632,83 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
632 | header value. */ | 632 | header value. */ |
633 | return MHD_NO; | 633 | return MHD_NO; |
634 | } | 634 | } |
635 | /* 8 = 4 hexadecimal numbers for the timestamp */ | ||
636 | nonce_time = strtoul (nonce + len - 8, (char **)NULL, 16); | ||
637 | t = (uint32_t) MHD_monotonic_time(); | ||
638 | /* | ||
639 | * First level vetting for the nonce validity: if the timestamp | ||
640 | * attached to the nonce exceeds `nonce_timeout', then the nonce is | ||
641 | * invalid. | ||
642 | */ | ||
643 | if ( (t > nonce_time + nonce_timeout) || | ||
644 | (nonce_time + nonce_timeout < nonce_time) ) | ||
645 | { | ||
646 | /* too old */ | ||
647 | return MHD_INVALID_NONCE; | ||
648 | } | ||
649 | |||
650 | calculate_nonce (nonce_time, | ||
651 | connection->method, | ||
652 | connection->daemon->digest_auth_random, | ||
653 | connection->daemon->digest_auth_rand_size, | ||
654 | connection->url, | ||
655 | realm, | ||
656 | noncehashexp); | ||
657 | /* | ||
658 | * Second level vetting for the nonce validity | ||
659 | * if the timestamp attached to the nonce is valid | ||
660 | * and possibly fabricated (in case of an attack) | ||
661 | * the attacker must also know the random seed to be | ||
662 | * able to generate a "sane" nonce, which if he does | ||
663 | * not, the nonce fabrication process going to be | ||
664 | * very hard to achieve. | ||
665 | */ | ||
666 | |||
667 | if (0 != strcmp (nonce, noncehashexp)) | ||
668 | { | ||
669 | return MHD_INVALID_NONCE; | ||
670 | } | ||
671 | if ( (0 == lookup_sub_value (cnonce, | ||
672 | sizeof (cnonce), | ||
673 | header, "cnonce")) || | ||
674 | (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) || | ||
675 | ( (0 != strcmp (qop, "auth")) && | ||
676 | (0 != strcmp (qop, "")) ) || | ||
677 | (0 == lookup_sub_value (nc, sizeof (nc), header, "nc")) || | ||
678 | (0 == lookup_sub_value (response, sizeof (response), header, "response")) ) | ||
679 | { | ||
680 | #if HAVE_MESSAGES | ||
681 | MHD_DLOG (connection->daemon, | ||
682 | "Authentication failed, invalid format.\n"); | ||
683 | #endif | ||
684 | return MHD_NO; | ||
685 | } | ||
686 | nci = strtoul (nc, &end, 16); | ||
687 | if ( ('\0' != *end) || | ||
688 | ( (LONG_MAX == nci) && | ||
689 | (ERANGE == errno) ) ) | ||
690 | { | ||
691 | #if HAVE_MESSAGES | ||
692 | MHD_DLOG (connection->daemon, | ||
693 | "Authentication failed, invalid format.\n"); | ||
694 | #endif | ||
695 | return MHD_NO; /* invalid nonce format */ | ||
696 | } | ||
697 | /* | ||
698 | * Checking if that combination of nonce and nc is sound | ||
699 | * and not a replay attack attempt. Also adds the nonce | ||
700 | * to the nonce-nc map if it does not exist there. | ||
701 | */ | ||
702 | |||
703 | if (MHD_YES != check_nonce_nc (connection, nonce, nci)) | ||
704 | { | ||
705 | return MHD_NO; | ||
706 | } | ||
707 | |||
635 | { | 708 | { |
636 | char *uri; | 709 | char *uri; |
637 | 710 | ||
638 | uri = malloc(left + 1); | 711 | uri = malloc (left + 1); |
639 | if (NULL == uri) | 712 | if (NULL == uri) |
640 | { | 713 | { |
641 | #if HAVE_MESSAGES | 714 | #if HAVE_MESSAGES |
@@ -648,24 +721,31 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
648 | left + 1, | 721 | left + 1, |
649 | header, "uri")) | 722 | header, "uri")) |
650 | { | 723 | { |
651 | free(uri); | 724 | free (uri); |
652 | return MHD_NO; | 725 | return MHD_NO; |
653 | } | 726 | } |
654 | 727 | ||
655 | /* 8 = 4 hexadecimal numbers for the timestamp */ | 728 | digest_calc_ha1("md5", |
656 | nonce_time = strtoul (nonce + len - 8, (char **)NULL, 16); | 729 | username, |
657 | t = (uint32_t) MHD_monotonic_time(); | 730 | realm, |
658 | /* | 731 | password, |
659 | * First level vetting for the nonce validity: if the timestamp | 732 | nonce, |
660 | * attached to the nonce exceeds `nonce_timeout', then the nonce is | 733 | cnonce, |
661 | * invalid. | 734 | ha1); |
662 | */ | 735 | digest_calc_response (ha1, |
663 | if ( (t > nonce_time + nonce_timeout) || | 736 | nonce, |
664 | (nonce_time + nonce_timeout < nonce_time) ) | 737 | nc, |
665 | { | 738 | cnonce, |
666 | free(uri); | 739 | qop, |
667 | return MHD_INVALID_NONCE; | 740 | connection->method, |
668 | } | 741 | uri, |
742 | hentity, | ||
743 | respexp); | ||
744 | |||
745 | /* Need to unescape URI before comparing with connection->url */ | ||
746 | connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls, | ||
747 | connection, | ||
748 | uri); | ||
669 | if (0 != strncmp (uri, | 749 | if (0 != strncmp (uri, |
670 | connection->url, | 750 | connection->url, |
671 | strlen (connection->url))) | 751 | strlen (connection->url))) |
@@ -674,9 +754,10 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
674 | MHD_DLOG (connection->daemon, | 754 | MHD_DLOG (connection->daemon, |
675 | "Authentication failed, URI does not match.\n"); | 755 | "Authentication failed, URI does not match.\n"); |
676 | #endif | 756 | #endif |
677 | free(uri); | 757 | free (uri); |
678 | return MHD_NO; | 758 | return MHD_NO; |
679 | } | 759 | } |
760 | |||
680 | { | 761 | { |
681 | const char *args = strchr (uri, '?'); | 762 | const char *args = strchr (uri, '?'); |
682 | 763 | ||
@@ -692,89 +773,11 @@ MHD_digest_auth_check (struct MHD_Connection *connection, | |||
692 | MHD_DLOG (connection->daemon, | 773 | MHD_DLOG (connection->daemon, |
693 | "Authentication failed, arguments do not match.\n"); | 774 | "Authentication failed, arguments do not match.\n"); |
694 | #endif | 775 | #endif |
695 | free(uri); | 776 | free (uri); |
696 | return MHD_NO; | 777 | return MHD_NO; |
697 | } | 778 | } |
698 | } | 779 | } |
699 | calculate_nonce (nonce_time, | 780 | free (uri); |
700 | connection->method, | ||
701 | connection->daemon->digest_auth_random, | ||
702 | connection->daemon->digest_auth_rand_size, | ||
703 | connection->url, | ||
704 | realm, | ||
705 | noncehashexp); | ||
706 | /* | ||
707 | * Second level vetting for the nonce validity | ||
708 | * if the timestamp attached to the nonce is valid | ||
709 | * and possibly fabricated (in case of an attack) | ||
710 | * the attacker must also know the random seed to be | ||
711 | * able to generate a "sane" nonce, which if he does | ||
712 | * not, the nonce fabrication process going to be | ||
713 | * very hard to achieve. | ||
714 | */ | ||
715 | |||
716 | if (0 != strcmp (nonce, noncehashexp)) | ||
717 | { | ||
718 | free(uri); | ||
719 | return MHD_INVALID_NONCE; | ||
720 | } | ||
721 | if ( (0 == lookup_sub_value (cnonce, | ||
722 | sizeof (cnonce), | ||
723 | header, "cnonce")) || | ||
724 | (0 == lookup_sub_value (qop, sizeof (qop), header, "qop")) || | ||
725 | ( (0 != strcmp (qop, "auth")) && | ||
726 | (0 != strcmp (qop, "")) ) || | ||
727 | (0 == lookup_sub_value (nc, sizeof (nc), header, "nc")) || | ||
728 | (0 == lookup_sub_value (response, sizeof (response), header, "response")) ) | ||
729 | { | ||
730 | #if HAVE_MESSAGES | ||
731 | MHD_DLOG (connection->daemon, | ||
732 | "Authentication failed, invalid format.\n"); | ||
733 | #endif | ||
734 | free(uri); | ||
735 | return MHD_NO; | ||
736 | } | ||
737 | nci = strtoul (nc, &end, 16); | ||
738 | if ( ('\0' != *end) || | ||
739 | ( (LONG_MAX == nci) && | ||
740 | (ERANGE == errno) ) ) | ||
741 | { | ||
742 | #if HAVE_MESSAGES | ||
743 | MHD_DLOG (connection->daemon, | ||
744 | "Authentication failed, invalid format.\n"); | ||
745 | #endif | ||
746 | free(uri); | ||
747 | return MHD_NO; /* invalid nonce format */ | ||
748 | } | ||
749 | /* | ||
750 | * Checking if that combination of nonce and nc is sound | ||
751 | * and not a replay attack attempt. Also adds the nonce | ||
752 | * to the nonce-nc map if it does not exist there. | ||
753 | */ | ||
754 | |||
755 | if (MHD_YES != check_nonce_nc (connection, nonce, nci)) | ||
756 | { | ||
757 | free(uri); | ||
758 | return MHD_NO; | ||
759 | } | ||
760 | |||
761 | digest_calc_ha1("md5", | ||
762 | username, | ||
763 | realm, | ||
764 | password, | ||
765 | nonce, | ||
766 | cnonce, | ||
767 | ha1); | ||
768 | digest_calc_response (ha1, | ||
769 | nonce, | ||
770 | nc, | ||
771 | cnonce, | ||
772 | qop, | ||
773 | connection->method, | ||
774 | uri, | ||
775 | hentity, | ||
776 | respexp); | ||
777 | free(uri); | ||
778 | return (0 == strcmp(response, respexp)) | 781 | return (0 == strcmp(response, respexp)) |
779 | ? MHD_YES | 782 | ? MHD_YES |
780 | : MHD_NO; | 783 | : MHD_NO; |
@@ -835,7 +838,7 @@ MHD_queue_auth_fail_response (struct MHD_Connection *connection, | |||
835 | : ""); | 838 | : ""); |
836 | { | 839 | { |
837 | char *header; | 840 | char *header; |
838 | 841 | ||
839 | header = malloc(hlen + 1); | 842 | header = malloc(hlen + 1); |
840 | if (NULL == header) | 843 | if (NULL == header) |
841 | { | 844 | { |