Mercurial > pidgin
comparison src/cipher.c @ 12382:cfc808463763
[gaim-migrate @ 14688]
Reimplement HTTP Digest Authentication (RFC 2617) as part of the Cipher API
committer: Tailor Script <tailor@pidgin.im>
| author | Richard Laager <rlaager@wiktel.com> |
|---|---|
| date | Wed, 07 Dec 2005 04:50:36 +0000 |
| parents | 8004885fabbe |
| children | 4e045668b9d0 |
comparison
equal
deleted
inserted
replaced
| 12381:29e237c4141b | 12382:cfc808463763 |
|---|---|
| 1778 gaim_cipher_context_get_data(GaimCipherContext *context) { | 1778 gaim_cipher_context_get_data(GaimCipherContext *context) { |
| 1779 g_return_val_if_fail(context, NULL); | 1779 g_return_val_if_fail(context, NULL); |
| 1780 | 1780 |
| 1781 return context->data; | 1781 return context->data; |
| 1782 } | 1782 } |
| 1783 | |
| 1784 gchar *gaim_cipher_http_digest_calculate_session_key( | |
| 1785 const gchar *algorithm, | |
| 1786 const gchar *username, | |
| 1787 const gchar *realm, | |
| 1788 const gchar *password, | |
| 1789 const gchar *nonce, | |
| 1790 const gchar *client_nonce) | |
| 1791 { | |
| 1792 GaimCipher *cipher; | |
| 1793 GaimCipherContext *context; | |
| 1794 gchar hash[32]; /* We only support MD5. */ | |
| 1795 | |
| 1796 g_return_val_if_fail(username != NULL, NULL); | |
| 1797 g_return_val_if_fail(realm != NULL, NULL); | |
| 1798 g_return_val_if_fail(password != NULL, NULL); | |
| 1799 g_return_val_if_fail(nonce != NULL, NULL); | |
| 1800 | |
| 1801 /* Check for a supported algorithm. */ | |
| 1802 g_return_val_if_fail(algorithm == NULL || | |
| 1803 *algorithm == '\0' || | |
| 1804 strcasecmp(algorithm, "MD5") || | |
| 1805 strcasecmp(algorithm, "MD5-sess"), NULL); | |
| 1806 | |
| 1807 cipher = gaim_ciphers_find_cipher("md5"); | |
| 1808 g_return_val_if_fail(cipher != NULL, NULL); | |
| 1809 | |
| 1810 context = gaim_cipher_context_new(cipher, NULL); | |
| 1811 | |
| 1812 gaim_cipher_context_append(context, (guchar *)username, strlen(username)); | |
| 1813 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1814 gaim_cipher_context_append(context, (guchar *)realm, strlen(realm)); | |
| 1815 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1816 gaim_cipher_context_append(context, (guchar *)password, strlen(password)); | |
| 1817 | |
| 1818 if (algorithm != NULL && !strcasecmp(algorithm, "MD5-sess")) | |
| 1819 { | |
| 1820 guchar digest[16]; | |
| 1821 | |
| 1822 if (client_nonce == NULL) | |
| 1823 { | |
| 1824 gaim_cipher_context_destroy(context); | |
| 1825 gaim_debug_error("cipher", "Required client_nonce missing for MD5-sess digest calculation."); | |
| 1826 return NULL; | |
| 1827 } | |
| 1828 | |
| 1829 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); | |
| 1830 gaim_cipher_context_destroy(context); | |
| 1831 | |
| 1832 context = gaim_cipher_context_new(cipher, NULL); | |
| 1833 gaim_cipher_context_append(context, digest, sizeof(digest)); | |
| 1834 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1835 gaim_cipher_context_append(context, (guchar *)nonce, strlen(nonce)); | |
| 1836 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1837 gaim_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce)); | |
| 1838 } | |
| 1839 | |
| 1840 gaim_cipher_context_digest_to_str(context, sizeof(hash), hash, NULL); | |
| 1841 gaim_cipher_context_destroy(context); | |
| 1842 | |
| 1843 return g_strdup(hash); | |
| 1844 } | |
| 1845 | |
| 1846 gchar *gaim_cipher_http_digest_calculate_response( | |
| 1847 const gchar *algorithm, | |
| 1848 const gchar *method, | |
| 1849 const gchar *digest_uri, | |
| 1850 const gchar *qop, | |
| 1851 const gchar *hashed_entity, | |
| 1852 size_t hashed_entity_len, | |
| 1853 const gchar *nonce, | |
| 1854 const gchar *nonce_count, | |
| 1855 const gchar *client_nonce, | |
| 1856 const gchar *session_key) | |
| 1857 { | |
| 1858 GaimCipher *cipher; | |
| 1859 GaimCipherContext *context; | |
| 1860 gchar hash2[32]; /* We only support MD5. */ | |
| 1861 | |
| 1862 g_return_val_if_fail(method != NULL, NULL); | |
| 1863 g_return_val_if_fail(digest_uri != NULL, NULL); | |
| 1864 g_return_val_if_fail(nonce != NULL, NULL); | |
| 1865 g_return_val_if_fail(session_key != NULL, NULL); | |
| 1866 | |
| 1867 /* Check for a supported algorithm. */ | |
| 1868 g_return_val_if_fail(algorithm == NULL || | |
| 1869 *algorithm == '\0' || | |
| 1870 strcasecmp(algorithm, "MD5") || | |
| 1871 strcasecmp(algorithm, "MD5-sess"), NULL); | |
| 1872 | |
| 1873 /* Check for a supported "quality of protection". */ | |
| 1874 g_return_val_if_fail(qop == NULL || | |
| 1875 *qop == '\0' || | |
| 1876 strcasecmp(qop, "auth") || | |
| 1877 strcasecmp(qop, "auth-int"), NULL); | |
| 1878 | |
| 1879 cipher = gaim_ciphers_find_cipher("md5"); | |
| 1880 g_return_val_if_fail(cipher != NULL, NULL); | |
| 1881 | |
| 1882 context = gaim_cipher_context_new(cipher, NULL); | |
| 1883 | |
| 1884 gaim_cipher_context_append(context, (guchar *)method, strlen(method)); | |
| 1885 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1886 gaim_cipher_context_append(context, (guchar *)digest_uri, strlen(digest_uri)); | |
| 1887 | |
| 1888 if (qop != NULL && !strcasecmp(qop, "auth-int")) | |
| 1889 { | |
| 1890 if (hashed_entity == NULL) | |
| 1891 { | |
| 1892 gaim_cipher_context_destroy(context); | |
| 1893 gaim_debug_error("cipher", "Required hashed_entity missing for auth-int digest calculation."); | |
| 1894 return NULL; | |
| 1895 } | |
| 1896 | |
| 1897 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1898 gaim_cipher_context_append(context, (guchar *)hashed_entity, hashed_entity_len); | |
| 1899 } | |
| 1900 | |
| 1901 gaim_cipher_context_digest_to_str(context, sizeof(hash2), hash2, NULL); | |
| 1902 gaim_cipher_context_destroy(context); | |
| 1903 | |
| 1904 context = gaim_cipher_context_new(cipher, NULL); | |
| 1905 gaim_cipher_context_append(context, (guchar *)session_key, strlen(session_key)); | |
| 1906 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1907 gaim_cipher_context_append(context, (guchar *)nonce, strlen(nonce)); | |
| 1908 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1909 | |
| 1910 if (qop != NULL && *qop != '\0') | |
| 1911 { | |
| 1912 if (nonce_count == NULL) | |
| 1913 { | |
| 1914 gaim_cipher_context_destroy(context); | |
| 1915 gaim_debug_error("cipher", "Required nonce_count missing for digest calculation."); | |
| 1916 return NULL; | |
| 1917 } | |
| 1918 | |
| 1919 if (client_nonce == NULL) | |
| 1920 { | |
| 1921 gaim_cipher_context_destroy(context); | |
| 1922 gaim_debug_error("cipher", "Required client_nonce missing for digest calculation."); | |
| 1923 return NULL; | |
| 1924 } | |
| 1925 | |
| 1926 gaim_cipher_context_append(context, (guchar *)nonce_count, strlen(nonce_count)); | |
| 1927 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1928 gaim_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce)); | |
| 1929 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1930 | |
| 1931 if (qop != NULL) | |
| 1932 gaim_cipher_context_append(context, (guchar *)qop, strlen(qop)); | |
| 1933 else | |
| 1934 gaim_cipher_context_append(context, (guchar *)"", 0); | |
| 1935 | |
| 1936 gaim_cipher_context_append(context, (guchar *)":", 1); | |
| 1937 } | |
| 1938 | |
| 1939 gaim_cipher_context_append(context, (guchar *)hash2, strlen(hash2)); | |
| 1940 gaim_cipher_context_digest_to_str(context, sizeof(hash2), hash2, NULL); | |
| 1941 gaim_cipher_context_destroy(context); | |
| 1942 | |
| 1943 return g_strdup(hash2); | |
| 1944 } |
