diff options
author | Jay Threeth | 2011-04-04 11:48:26 -0700 |
---|---|---|
committer | Jay Threeth | 2011-04-04 11:48:26 -0700 |
commit | 3c9cc506f741b980565ff5b3b001cd8b6ee36b12 (patch) | |
tree | cb862c57b3d5f74177cde3bd962a53fc377166f6 /linden/indra/libotr/libotr-3.2.0/src | |
parent | build fixes, might build on linux now (diff) | |
download | meta-impy-3c9cc506f741b980565ff5b3b001cd8b6ee36b12.zip meta-impy-3c9cc506f741b980565ff5b3b001cd8b6ee36b12.tar.gz meta-impy-3c9cc506f741b980565ff5b3b001cd8b6ee36b12.tar.bz2 meta-impy-3c9cc506f741b980565ff5b3b001cd8b6ee36b12.tar.xz |
add source to libraries, and cruft for building under windows
Diffstat (limited to 'linden/indra/libotr/libotr-3.2.0/src')
27 files changed, 8768 insertions, 0 deletions
diff --git a/linden/indra/libotr/libotr-3.2.0/src/Makefile.am b/linden/indra/libotr/libotr-3.2.0/src/Makefile.am new file mode 100755 index 0000000..c75fcbe --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/Makefile.am | |||
@@ -0,0 +1,13 @@ | |||
1 | INCLUDES = @LIBGCRYPT_CFLAGS@ | ||
2 | |||
3 | lib_LTLIBRARIES = libotr.la | ||
4 | |||
5 | libotr_la_SOURCES = privkey.c context.c proto.c b64.c dh.c mem.c message.c \ | ||
6 | userstate.c tlv.c auth.c sm.c | ||
7 | |||
8 | libotr_la_LDFLAGS = -version-info @LIBOTR_LIBTOOL_VERSION@ @LIBS@ @LIBGCRYPT_LIBS@ | ||
9 | |||
10 | otrincdir = $(includedir)/libotr | ||
11 | |||
12 | otrinc_HEADERS = b64.h context.h dh.h mem.h message.h privkey.h proto.h \ | ||
13 | version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/Makefile.in b/linden/indra/libotr/libotr-3.2.0/src/Makefile.in new file mode 100755 index 0000000..5de6fb4 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/Makefile.in | |||
@@ -0,0 +1,494 @@ | |||
1 | # Makefile.in generated by automake 1.9.6 from Makefile.am. | ||
2 | # @configure_input@ | ||
3 | |||
4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | ||
5 | # 2003, 2004, 2005 Free Software Foundation, Inc. | ||
6 | # This Makefile.in is free software; the Free Software Foundation | ||
7 | # gives unlimited permission to copy and/or distribute it, | ||
8 | # with or without modifications, as long as this notice is preserved. | ||
9 | |||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without | ||
12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
13 | # PARTICULAR PURPOSE. | ||
14 | |||
15 | @SET_MAKE@ | ||
16 | |||
17 | |||
18 | srcdir = @srcdir@ | ||
19 | top_srcdir = @top_srcdir@ | ||
20 | VPATH = @srcdir@ | ||
21 | pkgdatadir = $(datadir)/@PACKAGE@ | ||
22 | pkglibdir = $(libdir)/@PACKAGE@ | ||
23 | pkgincludedir = $(includedir)/@PACKAGE@ | ||
24 | top_builddir = .. | ||
25 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd | ||
26 | INSTALL = @INSTALL@ | ||
27 | install_sh_DATA = $(install_sh) -c -m 644 | ||
28 | install_sh_PROGRAM = $(install_sh) -c | ||
29 | install_sh_SCRIPT = $(install_sh) -c | ||
30 | INSTALL_HEADER = $(INSTALL_DATA) | ||
31 | transform = $(program_transform_name) | ||
32 | NORMAL_INSTALL = : | ||
33 | PRE_INSTALL = : | ||
34 | POST_INSTALL = : | ||
35 | NORMAL_UNINSTALL = : | ||
36 | PRE_UNINSTALL = : | ||
37 | POST_UNINSTALL = : | ||
38 | build_triplet = @build@ | ||
39 | host_triplet = @host@ | ||
40 | subdir = src | ||
41 | DIST_COMMON = $(otrinc_HEADERS) $(srcdir)/Makefile.am \ | ||
42 | $(srcdir)/Makefile.in | ||
43 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ||
44 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac | ||
45 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ | ||
46 | $(ACLOCAL_M4) | ||
47 | mkinstalldirs = $(install_sh) -d | ||
48 | CONFIG_HEADER = $(top_builddir)/config.h | ||
49 | CONFIG_CLEAN_FILES = | ||
50 | am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; | ||
51 | am__vpath_adj = case $$p in \ | ||
52 | $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ | ||
53 | *) f=$$p;; \ | ||
54 | esac; | ||
55 | am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; | ||
56 | am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(otrincdir)" | ||
57 | libLTLIBRARIES_INSTALL = $(INSTALL) | ||
58 | LTLIBRARIES = $(lib_LTLIBRARIES) | ||
59 | libotr_la_LIBADD = | ||
60 | am_libotr_la_OBJECTS = privkey.lo context.lo proto.lo b64.lo dh.lo \ | ||
61 | mem.lo message.lo userstate.lo tlv.lo auth.lo sm.lo | ||
62 | libotr_la_OBJECTS = $(am_libotr_la_OBJECTS) | ||
63 | DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) | ||
64 | depcomp = $(SHELL) $(top_srcdir)/depcomp | ||
65 | am__depfiles_maybe = depfiles | ||
66 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ | ||
67 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) | ||
68 | LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ | ||
69 | $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | ||
70 | $(AM_CFLAGS) $(CFLAGS) | ||
71 | CCLD = $(CC) | ||
72 | LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ | ||
73 | $(AM_LDFLAGS) $(LDFLAGS) -o $@ | ||
74 | SOURCES = $(libotr_la_SOURCES) | ||
75 | DIST_SOURCES = $(libotr_la_SOURCES) | ||
76 | otrincHEADERS_INSTALL = $(INSTALL_HEADER) | ||
77 | HEADERS = $(otrinc_HEADERS) | ||
78 | ETAGS = etags | ||
79 | CTAGS = ctags | ||
80 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | ||
81 | ACLOCAL = @ACLOCAL@ | ||
82 | AMDEP_FALSE = @AMDEP_FALSE@ | ||
83 | AMDEP_TRUE = @AMDEP_TRUE@ | ||
84 | AMTAR = @AMTAR@ | ||
85 | AR = @AR@ | ||
86 | AUTOCONF = @AUTOCONF@ | ||
87 | AUTOHEADER = @AUTOHEADER@ | ||
88 | AUTOMAKE = @AUTOMAKE@ | ||
89 | AWK = @AWK@ | ||
90 | CC = @CC@ | ||
91 | CCDEPMODE = @CCDEPMODE@ | ||
92 | CFLAGS = @CFLAGS@ | ||
93 | CPP = @CPP@ | ||
94 | CPPFLAGS = @CPPFLAGS@ | ||
95 | CXX = @CXX@ | ||
96 | CXXCPP = @CXXCPP@ | ||
97 | CXXDEPMODE = @CXXDEPMODE@ | ||
98 | CXXFLAGS = @CXXFLAGS@ | ||
99 | CYGPATH_W = @CYGPATH_W@ | ||
100 | DEFS = @DEFS@ | ||
101 | DEPDIR = @DEPDIR@ | ||
102 | ECHO = @ECHO@ | ||
103 | ECHO_C = @ECHO_C@ | ||
104 | ECHO_N = @ECHO_N@ | ||
105 | ECHO_T = @ECHO_T@ | ||
106 | EGREP = @EGREP@ | ||
107 | EXEEXT = @EXEEXT@ | ||
108 | F77 = @F77@ | ||
109 | FFLAGS = @FFLAGS@ | ||
110 | INSTALL_DATA = @INSTALL_DATA@ | ||
111 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ | ||
112 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ | ||
113 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ | ||
114 | LDFLAGS = @LDFLAGS@ | ||
115 | LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ | ||
116 | LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ | ||
117 | LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ | ||
118 | LIBOBJS = @LIBOBJS@ | ||
119 | LIBOTR_LIBTOOL_VERSION = @LIBOTR_LIBTOOL_VERSION@ | ||
120 | LIBS = @LIBS@ | ||
121 | LIBTOOL = @LIBTOOL@ | ||
122 | LN_S = @LN_S@ | ||
123 | LTLIBOBJS = @LTLIBOBJS@ | ||
124 | MAKEINFO = @MAKEINFO@ | ||
125 | OBJEXT = @OBJEXT@ | ||
126 | PACKAGE = @PACKAGE@ | ||
127 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ | ||
128 | PACKAGE_NAME = @PACKAGE_NAME@ | ||
129 | PACKAGE_STRING = @PACKAGE_STRING@ | ||
130 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ | ||
131 | PACKAGE_VERSION = @PACKAGE_VERSION@ | ||
132 | PATH_SEPARATOR = @PATH_SEPARATOR@ | ||
133 | RANLIB = @RANLIB@ | ||
134 | SET_MAKE = @SET_MAKE@ | ||
135 | SHELL = @SHELL@ | ||
136 | STRIP = @STRIP@ | ||
137 | VERSION = @VERSION@ | ||
138 | ac_ct_AR = @ac_ct_AR@ | ||
139 | ac_ct_CC = @ac_ct_CC@ | ||
140 | ac_ct_CXX = @ac_ct_CXX@ | ||
141 | ac_ct_F77 = @ac_ct_F77@ | ||
142 | ac_ct_RANLIB = @ac_ct_RANLIB@ | ||
143 | ac_ct_STRIP = @ac_ct_STRIP@ | ||
144 | am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ | ||
145 | am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ | ||
146 | am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ | ||
147 | am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ | ||
148 | am__include = @am__include@ | ||
149 | am__leading_dot = @am__leading_dot@ | ||
150 | am__quote = @am__quote@ | ||
151 | am__tar = @am__tar@ | ||
152 | am__untar = @am__untar@ | ||
153 | bindir = @bindir@ | ||
154 | build = @build@ | ||
155 | build_alias = @build_alias@ | ||
156 | build_cpu = @build_cpu@ | ||
157 | build_os = @build_os@ | ||
158 | build_vendor = @build_vendor@ | ||
159 | datadir = @datadir@ | ||
160 | exec_prefix = @exec_prefix@ | ||
161 | host = @host@ | ||
162 | host_alias = @host_alias@ | ||
163 | host_cpu = @host_cpu@ | ||
164 | host_os = @host_os@ | ||
165 | host_vendor = @host_vendor@ | ||
166 | includedir = @includedir@ | ||
167 | infodir = @infodir@ | ||
168 | install_sh = @install_sh@ | ||
169 | libdir = @libdir@ | ||
170 | libexecdir = @libexecdir@ | ||
171 | localstatedir = @localstatedir@ | ||
172 | mandir = @mandir@ | ||
173 | mkdir_p = @mkdir_p@ | ||
174 | oldincludedir = @oldincludedir@ | ||
175 | prefix = @prefix@ | ||
176 | program_transform_name = @program_transform_name@ | ||
177 | sbindir = @sbindir@ | ||
178 | sharedstatedir = @sharedstatedir@ | ||
179 | sysconfdir = @sysconfdir@ | ||
180 | target_alias = @target_alias@ | ||
181 | INCLUDES = @LIBGCRYPT_CFLAGS@ | ||
182 | lib_LTLIBRARIES = libotr.la | ||
183 | libotr_la_SOURCES = privkey.c context.c proto.c b64.c dh.c mem.c message.c \ | ||
184 | userstate.c tlv.c auth.c sm.c | ||
185 | |||
186 | libotr_la_LDFLAGS = -version-info @LIBOTR_LIBTOOL_VERSION@ @LIBS@ @LIBGCRYPT_LIBS@ | ||
187 | otrincdir = $(includedir)/libotr | ||
188 | otrinc_HEADERS = b64.h context.h dh.h mem.h message.h privkey.h proto.h \ | ||
189 | version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h | ||
190 | |||
191 | all: all-am | ||
192 | |||
193 | .SUFFIXES: | ||
194 | .SUFFIXES: .c .lo .o .obj | ||
195 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) | ||
196 | @for dep in $?; do \ | ||
197 | case '$(am__configure_deps)' in \ | ||
198 | *$$dep*) \ | ||
199 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ | ||
200 | && exit 0; \ | ||
201 | exit 1;; \ | ||
202 | esac; \ | ||
203 | done; \ | ||
204 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ | ||
205 | cd $(top_srcdir) && \ | ||
206 | $(AUTOMAKE) --gnu src/Makefile | ||
207 | .PRECIOUS: Makefile | ||
208 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | ||
209 | @case '$?' in \ | ||
210 | *config.status*) \ | ||
211 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ | ||
212 | *) \ | ||
213 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | ||
214 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | ||
215 | esac; | ||
216 | |||
217 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) | ||
218 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
219 | |||
220 | $(top_srcdir)/configure: $(am__configure_deps) | ||
221 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
222 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) | ||
223 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
224 | install-libLTLIBRARIES: $(lib_LTLIBRARIES) | ||
225 | @$(NORMAL_INSTALL) | ||
226 | test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" | ||
227 | @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ | ||
228 | if test -f $$p; then \ | ||
229 | f=$(am__strip_dir) \ | ||
230 | echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ | ||
231 | $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ | ||
232 | else :; fi; \ | ||
233 | done | ||
234 | |||
235 | uninstall-libLTLIBRARIES: | ||
236 | @$(NORMAL_UNINSTALL) | ||
237 | @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ | ||
238 | p=$(am__strip_dir) \ | ||
239 | echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ | ||
240 | $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ | ||
241 | done | ||
242 | |||
243 | clean-libLTLIBRARIES: | ||
244 | -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) | ||
245 | @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ | ||
246 | dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ | ||
247 | test "$$dir" != "$$p" || dir=.; \ | ||
248 | echo "rm -f \"$${dir}/so_locations\""; \ | ||
249 | rm -f "$${dir}/so_locations"; \ | ||
250 | done | ||
251 | libotr.la: $(libotr_la_OBJECTS) $(libotr_la_DEPENDENCIES) | ||
252 | $(LINK) -rpath $(libdir) $(libotr_la_LDFLAGS) $(libotr_la_OBJECTS) $(libotr_la_LIBADD) $(LIBS) | ||
253 | |||
254 | mostlyclean-compile: | ||
255 | -rm -f *.$(OBJEXT) | ||
256 | |||
257 | distclean-compile: | ||
258 | -rm -f *.tab.c | ||
259 | |||
260 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Plo@am__quote@ | ||
261 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/b64.Plo@am__quote@ | ||
262 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context.Plo@am__quote@ | ||
263 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dh.Plo@am__quote@ | ||
264 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@ | ||
265 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Plo@am__quote@ | ||
266 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privkey.Plo@am__quote@ | ||
267 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto.Plo@am__quote@ | ||
268 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm.Plo@am__quote@ | ||
269 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tlv.Plo@am__quote@ | ||
270 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/userstate.Plo@am__quote@ | ||
271 | |||
272 | .c.o: | ||
273 | @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ | ||
274 | @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi | ||
275 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
276 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
277 | @am__fastdepCC_FALSE@ $(COMPILE) -c $< | ||
278 | |||
279 | .c.obj: | ||
280 | @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ | ||
281 | @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi | ||
282 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
283 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
284 | @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` | ||
285 | |||
286 | .c.lo: | ||
287 | @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ | ||
288 | @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi | ||
289 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ | ||
290 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
291 | @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< | ||
292 | |||
293 | mostlyclean-libtool: | ||
294 | -rm -f *.lo | ||
295 | |||
296 | clean-libtool: | ||
297 | -rm -rf .libs _libs | ||
298 | |||
299 | distclean-libtool: | ||
300 | -rm -f libtool | ||
301 | uninstall-info-am: | ||
302 | install-otrincHEADERS: $(otrinc_HEADERS) | ||
303 | @$(NORMAL_INSTALL) | ||
304 | test -z "$(otrincdir)" || $(mkdir_p) "$(DESTDIR)$(otrincdir)" | ||
305 | @list='$(otrinc_HEADERS)'; for p in $$list; do \ | ||
306 | if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ | ||
307 | f=$(am__strip_dir) \ | ||
308 | echo " $(otrincHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(otrincdir)/$$f'"; \ | ||
309 | $(otrincHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(otrincdir)/$$f"; \ | ||
310 | done | ||
311 | |||
312 | uninstall-otrincHEADERS: | ||
313 | @$(NORMAL_UNINSTALL) | ||
314 | @list='$(otrinc_HEADERS)'; for p in $$list; do \ | ||
315 | f=$(am__strip_dir) \ | ||
316 | echo " rm -f '$(DESTDIR)$(otrincdir)/$$f'"; \ | ||
317 | rm -f "$(DESTDIR)$(otrincdir)/$$f"; \ | ||
318 | done | ||
319 | |||
320 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) | ||
321 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
322 | unique=`for i in $$list; do \ | ||
323 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
324 | done | \ | ||
325 | $(AWK) ' { files[$$0] = 1; } \ | ||
326 | END { for (i in files) print i; }'`; \ | ||
327 | mkid -fID $$unique | ||
328 | tags: TAGS | ||
329 | |||
330 | TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | ||
331 | $(TAGS_FILES) $(LISP) | ||
332 | tags=; \ | ||
333 | here=`pwd`; \ | ||
334 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
335 | unique=`for i in $$list; do \ | ||
336 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
337 | done | \ | ||
338 | $(AWK) ' { files[$$0] = 1; } \ | ||
339 | END { for (i in files) print i; }'`; \ | ||
340 | if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ | ||
341 | test -n "$$unique" || unique=$$empty_fix; \ | ||
342 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | ||
343 | $$tags $$unique; \ | ||
344 | fi | ||
345 | ctags: CTAGS | ||
346 | CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | ||
347 | $(TAGS_FILES) $(LISP) | ||
348 | tags=; \ | ||
349 | here=`pwd`; \ | ||
350 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
351 | unique=`for i in $$list; do \ | ||
352 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
353 | done | \ | ||
354 | $(AWK) ' { files[$$0] = 1; } \ | ||
355 | END { for (i in files) print i; }'`; \ | ||
356 | test -z "$(CTAGS_ARGS)$$tags$$unique" \ | ||
357 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ | ||
358 | $$tags $$unique | ||
359 | |||
360 | GTAGS: | ||
361 | here=`$(am__cd) $(top_builddir) && pwd` \ | ||
362 | && cd $(top_srcdir) \ | ||
363 | && gtags -i $(GTAGS_ARGS) $$here | ||
364 | |||
365 | distclean-tags: | ||
366 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags | ||
367 | |||
368 | distdir: $(DISTFILES) | ||
369 | @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ | ||
370 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ | ||
371 | list='$(DISTFILES)'; for file in $$list; do \ | ||
372 | case $$file in \ | ||
373 | $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ | ||
374 | $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ | ||
375 | esac; \ | ||
376 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ | ||
377 | dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ | ||
378 | if test "$$dir" != "$$file" && test "$$dir" != "."; then \ | ||
379 | dir="/$$dir"; \ | ||
380 | $(mkdir_p) "$(distdir)$$dir"; \ | ||
381 | else \ | ||
382 | dir=''; \ | ||
383 | fi; \ | ||
384 | if test -d $$d/$$file; then \ | ||
385 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ | ||
386 | cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ | ||
387 | fi; \ | ||
388 | cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ | ||
389 | else \ | ||
390 | test -f $(distdir)/$$file \ | ||
391 | || cp -p $$d/$$file $(distdir)/$$file \ | ||
392 | || exit 1; \ | ||
393 | fi; \ | ||
394 | done | ||
395 | check-am: all-am | ||
396 | check: check-am | ||
397 | all-am: Makefile $(LTLIBRARIES) $(HEADERS) | ||
398 | installdirs: | ||
399 | for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(otrincdir)"; do \ | ||
400 | test -z "$$dir" || $(mkdir_p) "$$dir"; \ | ||
401 | done | ||
402 | install: install-am | ||
403 | install-exec: install-exec-am | ||
404 | install-data: install-data-am | ||
405 | uninstall: uninstall-am | ||
406 | |||
407 | install-am: all-am | ||
408 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am | ||
409 | |||
410 | installcheck: installcheck-am | ||
411 | install-strip: | ||
412 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ | ||
413 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ | ||
414 | `test -z '$(STRIP)' || \ | ||
415 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install | ||
416 | mostlyclean-generic: | ||
417 | |||
418 | clean-generic: | ||
419 | |||
420 | distclean-generic: | ||
421 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) | ||
422 | |||
423 | maintainer-clean-generic: | ||
424 | @echo "This command is intended for maintainers to use" | ||
425 | @echo "it deletes files that may require special tools to rebuild." | ||
426 | clean: clean-am | ||
427 | |||
428 | clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ | ||
429 | mostlyclean-am | ||
430 | |||
431 | distclean: distclean-am | ||
432 | -rm -rf ./$(DEPDIR) | ||
433 | -rm -f Makefile | ||
434 | distclean-am: clean-am distclean-compile distclean-generic \ | ||
435 | distclean-libtool distclean-tags | ||
436 | |||
437 | dvi: dvi-am | ||
438 | |||
439 | dvi-am: | ||
440 | |||
441 | html: html-am | ||
442 | |||
443 | info: info-am | ||
444 | |||
445 | info-am: | ||
446 | |||
447 | install-data-am: install-otrincHEADERS | ||
448 | |||
449 | install-exec-am: install-libLTLIBRARIES | ||
450 | |||
451 | install-info: install-info-am | ||
452 | |||
453 | install-man: | ||
454 | |||
455 | installcheck-am: | ||
456 | |||
457 | maintainer-clean: maintainer-clean-am | ||
458 | -rm -rf ./$(DEPDIR) | ||
459 | -rm -f Makefile | ||
460 | maintainer-clean-am: distclean-am maintainer-clean-generic | ||
461 | |||
462 | mostlyclean: mostlyclean-am | ||
463 | |||
464 | mostlyclean-am: mostlyclean-compile mostlyclean-generic \ | ||
465 | mostlyclean-libtool | ||
466 | |||
467 | pdf: pdf-am | ||
468 | |||
469 | pdf-am: | ||
470 | |||
471 | ps: ps-am | ||
472 | |||
473 | ps-am: | ||
474 | |||
475 | uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \ | ||
476 | uninstall-otrincHEADERS | ||
477 | |||
478 | .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ | ||
479 | clean-libLTLIBRARIES clean-libtool ctags distclean \ | ||
480 | distclean-compile distclean-generic distclean-libtool \ | ||
481 | distclean-tags distdir dvi dvi-am html html-am info info-am \ | ||
482 | install install-am install-data install-data-am install-exec \ | ||
483 | install-exec-am install-info install-info-am \ | ||
484 | install-libLTLIBRARIES install-man install-otrincHEADERS \ | ||
485 | install-strip installcheck installcheck-am installdirs \ | ||
486 | maintainer-clean maintainer-clean-generic mostlyclean \ | ||
487 | mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ | ||
488 | pdf pdf-am ps ps-am tags uninstall uninstall-am \ | ||
489 | uninstall-info-am uninstall-libLTLIBRARIES \ | ||
490 | uninstall-otrincHEADERS | ||
491 | |||
492 | # Tell versions [3.59,3.63) of GNU make to not export all variables. | ||
493 | # Otherwise a system limit (for SysV at least) may be exceeded. | ||
494 | .NOEXPORT: | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/auth.c b/linden/indra/libotr/libotr-3.2.0/src/auth.c new file mode 100755 index 0000000..e4445f6 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/auth.c | |||
@@ -0,0 +1,1413 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* system headers */ | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <assert.h> | ||
24 | |||
25 | /* libotr headers */ | ||
26 | #include "b64.h" | ||
27 | #include "privkey.h" | ||
28 | #include "auth.h" | ||
29 | #include "serial.h" | ||
30 | |||
31 | /* | ||
32 | * Initialize the fields of an OtrlAuthInfo (already allocated). | ||
33 | */ | ||
34 | void otrl_auth_new(OtrlAuthInfo *auth) | ||
35 | { | ||
36 | auth->authstate = OTRL_AUTHSTATE_NONE; | ||
37 | otrl_dh_keypair_init(&(auth->our_dh)); | ||
38 | auth->our_keyid = 0; | ||
39 | auth->encgx = NULL; | ||
40 | auth->encgx_len = 0; | ||
41 | memset(auth->r, 0, 16); | ||
42 | memset(auth->hashgx, 0, 32); | ||
43 | auth->their_pub = NULL; | ||
44 | auth->their_keyid = 0; | ||
45 | auth->enc_c = NULL; | ||
46 | auth->enc_cp = NULL; | ||
47 | auth->mac_m1 = NULL; | ||
48 | auth->mac_m1p = NULL; | ||
49 | auth->mac_m2 = NULL; | ||
50 | auth->mac_m2p = NULL; | ||
51 | memset(auth->their_fingerprint, 0, 20); | ||
52 | auth->initiated = 0; | ||
53 | auth->protocol_version = 0; | ||
54 | memset(auth->secure_session_id, 0, 20); | ||
55 | auth->secure_session_id_len = 0; | ||
56 | auth->lastauthmsg = NULL; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Clear the fields of an OtrlAuthInfo (but leave it allocated). | ||
61 | */ | ||
62 | void otrl_auth_clear(OtrlAuthInfo *auth) | ||
63 | { | ||
64 | auth->authstate = OTRL_AUTHSTATE_NONE; | ||
65 | otrl_dh_keypair_free(&(auth->our_dh)); | ||
66 | auth->our_keyid = 0; | ||
67 | free(auth->encgx); | ||
68 | auth->encgx = NULL; | ||
69 | auth->encgx_len = 0; | ||
70 | memset(auth->r, 0, 16); | ||
71 | memset(auth->hashgx, 0, 32); | ||
72 | gcry_mpi_release(auth->their_pub); | ||
73 | auth->their_pub = NULL; | ||
74 | auth->their_keyid = 0; | ||
75 | gcry_cipher_close(auth->enc_c); | ||
76 | gcry_cipher_close(auth->enc_cp); | ||
77 | gcry_md_close(auth->mac_m1); | ||
78 | gcry_md_close(auth->mac_m1p); | ||
79 | gcry_md_close(auth->mac_m2); | ||
80 | gcry_md_close(auth->mac_m2p); | ||
81 | auth->enc_c = NULL; | ||
82 | auth->enc_cp = NULL; | ||
83 | auth->mac_m1 = NULL; | ||
84 | auth->mac_m1p = NULL; | ||
85 | auth->mac_m2 = NULL; | ||
86 | auth->mac_m2p = NULL; | ||
87 | memset(auth->their_fingerprint, 0, 20); | ||
88 | auth->initiated = 0; | ||
89 | auth->protocol_version = 0; | ||
90 | memset(auth->secure_session_id, 0, 20); | ||
91 | auth->secure_session_id_len = 0; | ||
92 | free(auth->lastauthmsg); | ||
93 | auth->lastauthmsg = NULL; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Start a fresh AKE (version 2) using the given OtrlAuthInfo. Generate | ||
98 | * a fresh DH keypair to use. If no error is returned, the message to | ||
99 | * transmit will be contained in auth->lastauthmsg. | ||
100 | */ | ||
101 | gcry_error_t otrl_auth_start_v2(OtrlAuthInfo *auth) | ||
102 | { | ||
103 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
104 | const enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
105 | size_t npub; | ||
106 | gcry_cipher_hd_t enc = NULL; | ||
107 | unsigned char ctr[16]; | ||
108 | unsigned char *buf, *bufp; | ||
109 | size_t buflen, lenp; | ||
110 | |||
111 | /* Clear out this OtrlAuthInfo and start over */ | ||
112 | otrl_auth_clear(auth); | ||
113 | auth->initiated = 1; | ||
114 | |||
115 | otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); | ||
116 | auth->our_keyid = 1; | ||
117 | |||
118 | /* Pick an encryption key */ | ||
119 | gcry_randomize(auth->r, 16, GCRY_STRONG_RANDOM); | ||
120 | |||
121 | /* Allocate space for the encrypted g^x */ | ||
122 | gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub); | ||
123 | auth->encgx = malloc(4+npub); | ||
124 | if (auth->encgx == NULL) goto memerr; | ||
125 | auth->encgx_len = 4+npub; | ||
126 | bufp = auth->encgx; | ||
127 | lenp = auth->encgx_len; | ||
128 | write_mpi(auth->our_dh.pub, npub, "g^x"); | ||
129 | assert(lenp == 0); | ||
130 | |||
131 | /* Hash g^x */ | ||
132 | gcry_md_hash_buffer(GCRY_MD_SHA256, auth->hashgx, auth->encgx, | ||
133 | auth->encgx_len); | ||
134 | |||
135 | /* Encrypt g^x using the key r */ | ||
136 | err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, | ||
137 | GCRY_CIPHER_SECURE); | ||
138 | if (err) goto err; | ||
139 | |||
140 | err = gcry_cipher_setkey(enc, auth->r, 16); | ||
141 | if (err) goto err; | ||
142 | |||
143 | memset(ctr, 0, 16); | ||
144 | err = gcry_cipher_setctr(enc, ctr, 16); | ||
145 | if (err) goto err; | ||
146 | |||
147 | err = gcry_cipher_encrypt(enc, auth->encgx, auth->encgx_len, NULL, 0); | ||
148 | if (err) goto err; | ||
149 | |||
150 | gcry_cipher_close(enc); | ||
151 | enc = NULL; | ||
152 | |||
153 | /* Now serialize the message */ | ||
154 | lenp = 3 + 4 + auth->encgx_len + 4 + 32; | ||
155 | bufp = malloc(lenp); | ||
156 | if (bufp == NULL) goto memerr; | ||
157 | buf = bufp; | ||
158 | buflen = lenp; | ||
159 | |||
160 | memmove(bufp, "\x00\x02\x02", 3); /* header */ | ||
161 | debug_data("Header", bufp, 3); | ||
162 | bufp += 3; lenp -= 3; | ||
163 | |||
164 | /* Encrypted g^x */ | ||
165 | write_int(auth->encgx_len); | ||
166 | debug_int("Enc gx len", bufp-4); | ||
167 | memmove(bufp, auth->encgx, auth->encgx_len); | ||
168 | debug_data("Enc gx", bufp, auth->encgx_len); | ||
169 | bufp += auth->encgx_len; lenp -= auth->encgx_len; | ||
170 | |||
171 | /* Hashed g^x */ | ||
172 | write_int(32); | ||
173 | debug_int("hashgx len", bufp-4); | ||
174 | memmove(bufp, auth->hashgx, 32); | ||
175 | debug_data("hashgx", bufp, 32); | ||
176 | bufp += 32; lenp -= 32; | ||
177 | |||
178 | assert(lenp == 0); | ||
179 | |||
180 | auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); | ||
181 | free(buf); | ||
182 | if (auth->lastauthmsg == NULL) goto memerr; | ||
183 | auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY; | ||
184 | |||
185 | return err; | ||
186 | |||
187 | memerr: | ||
188 | err = gcry_error(GPG_ERR_ENOMEM); | ||
189 | err: | ||
190 | otrl_auth_clear(auth); | ||
191 | gcry_cipher_close(enc); | ||
192 | return err; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Create a D-H Key Message using the our_dh value in the given auth, | ||
197 | * and store it in auth->lastauthmsg. | ||
198 | */ | ||
199 | static gcry_error_t create_key_message(OtrlAuthInfo *auth) | ||
200 | { | ||
201 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
202 | const enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
203 | unsigned char *buf, *bufp; | ||
204 | size_t buflen, lenp; | ||
205 | size_t npub; | ||
206 | |||
207 | gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub); | ||
208 | buflen = 3 + 4 + npub; | ||
209 | buf = malloc(buflen); | ||
210 | if (buf == NULL) goto memerr; | ||
211 | bufp = buf; | ||
212 | lenp = buflen; | ||
213 | |||
214 | memmove(bufp, "\x00\x02\x0a", 3); /* header */ | ||
215 | debug_data("Header", bufp, 3); | ||
216 | bufp += 3; lenp -= 3; | ||
217 | |||
218 | /* g^y */ | ||
219 | write_mpi(auth->our_dh.pub, npub, "g^y"); | ||
220 | |||
221 | assert(lenp == 0); | ||
222 | |||
223 | free(auth->lastauthmsg); | ||
224 | auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); | ||
225 | free(buf); | ||
226 | if (auth->lastauthmsg == NULL) goto memerr; | ||
227 | |||
228 | return err; | ||
229 | |||
230 | memerr: | ||
231 | err = gcry_error(GPG_ERR_ENOMEM); | ||
232 | return err; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Handle an incoming D-H Commit Message. If no error is returned, the | ||
237 | * message to send will be left in auth->lastauthmsg. Generate a fresh | ||
238 | * keypair to use. | ||
239 | */ | ||
240 | gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth, | ||
241 | const char *commitmsg) | ||
242 | { | ||
243 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
244 | unsigned char *buf = NULL, *bufp = NULL, *encbuf = NULL; | ||
245 | unsigned char hashbuf[32]; | ||
246 | size_t buflen, lenp, enclen, hashlen; | ||
247 | int res; | ||
248 | |||
249 | res = otrl_base64_otr_decode(commitmsg, &buf, &buflen); | ||
250 | if (res == -1) goto memerr; | ||
251 | if (res == -2) goto invval; | ||
252 | |||
253 | bufp = buf; | ||
254 | lenp = buflen; | ||
255 | |||
256 | /* Header */ | ||
257 | require_len(3); | ||
258 | if (memcmp(bufp, "\x00\x02\x02", 3)) goto invval; | ||
259 | bufp += 3; lenp -= 3; | ||
260 | |||
261 | /* Encrypted g^x */ | ||
262 | read_int(enclen); | ||
263 | require_len(enclen); | ||
264 | encbuf = malloc(enclen); | ||
265 | if (encbuf == NULL && enclen > 0) goto memerr; | ||
266 | memmove(encbuf, bufp, enclen); | ||
267 | bufp += enclen; lenp -= enclen; | ||
268 | |||
269 | /* Hashed g^x */ | ||
270 | read_int(hashlen); | ||
271 | if (hashlen != 32) goto invval; | ||
272 | require_len(32); | ||
273 | memmove(hashbuf, bufp, 32); | ||
274 | bufp += 32; lenp -= 32; | ||
275 | |||
276 | if (lenp != 0) goto invval; | ||
277 | free(buf); | ||
278 | buf = NULL; | ||
279 | |||
280 | switch(auth->authstate) { | ||
281 | case OTRL_AUTHSTATE_NONE: | ||
282 | case OTRL_AUTHSTATE_AWAITING_SIG: | ||
283 | case OTRL_AUTHSTATE_V1_SETUP: | ||
284 | |||
285 | /* Store the incoming information */ | ||
286 | otrl_auth_clear(auth); | ||
287 | otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); | ||
288 | auth->our_keyid = 1; | ||
289 | auth->encgx = encbuf; | ||
290 | encbuf = NULL; | ||
291 | auth->encgx_len = enclen; | ||
292 | memmove(auth->hashgx, hashbuf, 32); | ||
293 | |||
294 | /* Create a D-H Key Message */ | ||
295 | err = create_key_message(auth); | ||
296 | if (err) goto err; | ||
297 | auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG; | ||
298 | |||
299 | break; | ||
300 | |||
301 | case OTRL_AUTHSTATE_AWAITING_DHKEY: | ||
302 | /* We sent a D-H Commit Message, and we also received one | ||
303 | * back. Compare the hashgx values to see which one wins. */ | ||
304 | if (memcmp(auth->hashgx, hashbuf, 32) > 0) { | ||
305 | /* Ours wins. Ignore the message we received, and just | ||
306 | * resend the same D-H Commit message again. */ | ||
307 | free(encbuf); | ||
308 | encbuf = NULL; | ||
309 | } else { | ||
310 | /* Ours loses. Use the incoming parameters instead. */ | ||
311 | otrl_auth_clear(auth); | ||
312 | otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); | ||
313 | auth->our_keyid = 1; | ||
314 | auth->encgx = encbuf; | ||
315 | encbuf = NULL; | ||
316 | auth->encgx_len = enclen; | ||
317 | memmove(auth->hashgx, hashbuf, 32); | ||
318 | |||
319 | /* Create a D-H Key Message */ | ||
320 | err = create_key_message(auth); | ||
321 | if (err) goto err; | ||
322 | auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG; | ||
323 | } | ||
324 | break; | ||
325 | case OTRL_AUTHSTATE_AWAITING_REVEALSIG: | ||
326 | /* Use the incoming parameters, but just retransmit the old | ||
327 | * D-H Key Message. */ | ||
328 | free(auth->encgx); | ||
329 | auth->encgx = encbuf; | ||
330 | encbuf = NULL; | ||
331 | auth->encgx_len = enclen; | ||
332 | memmove(auth->hashgx, hashbuf, 32); | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | return err; | ||
337 | |||
338 | invval: | ||
339 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
340 | goto err; | ||
341 | memerr: | ||
342 | err = gcry_error(GPG_ERR_ENOMEM); | ||
343 | err: | ||
344 | free(buf); | ||
345 | free(encbuf); | ||
346 | return err; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * Calculate the encrypted part of the Reveal Signature and Signature | ||
351 | * Messages, given a MAC key, an encryption key, two DH public keys, an | ||
352 | * authentication public key (contained in an OtrlPrivKey structure), | ||
353 | * and a keyid. If no error is returned, *authbufp will point to the | ||
354 | * result, and *authlenp will point to its length. | ||
355 | */ | ||
356 | static gcry_error_t calculate_pubkey_auth(unsigned char **authbufp, | ||
357 | size_t *authlenp, gcry_md_hd_t mackey, gcry_cipher_hd_t enckey, | ||
358 | gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub, | ||
359 | OtrlPrivKey *privkey, unsigned int keyid) | ||
360 | { | ||
361 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
362 | const enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
363 | size_t ourpublen, theirpublen, totallen, lenp; | ||
364 | unsigned char *buf = NULL, *bufp = NULL; | ||
365 | unsigned char macbuf[32]; | ||
366 | unsigned char *sigbuf = NULL; | ||
367 | size_t siglen; | ||
368 | |||
369 | /* How big are the DH public keys? */ | ||
370 | gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub); | ||
371 | gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub); | ||
372 | |||
373 | /* How big is the total structure to be MAC'd? */ | ||
374 | totallen = 4 + ourpublen + 4 + theirpublen + 2 + privkey->pubkey_datalen | ||
375 | + 4; | ||
376 | buf = malloc(totallen); | ||
377 | if (buf == NULL) goto memerr; | ||
378 | |||
379 | bufp = buf; | ||
380 | lenp = totallen; | ||
381 | |||
382 | /* Write the data to be MAC'd */ | ||
383 | write_mpi(our_dh_pub, ourpublen, "Our DH pubkey"); | ||
384 | write_mpi(their_dh_pub, theirpublen, "Their DH pubkey"); | ||
385 | bufp[0] = ((privkey->pubkey_type) >> 8) & 0xff; | ||
386 | bufp[1] = (privkey->pubkey_type) & 0xff; | ||
387 | bufp += 2; lenp -= 2; | ||
388 | memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen); | ||
389 | debug_data("Pubkey", bufp, privkey->pubkey_datalen); | ||
390 | bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen; | ||
391 | write_int(keyid); | ||
392 | debug_int("Keyid", bufp-4); | ||
393 | |||
394 | assert(lenp == 0); | ||
395 | |||
396 | /* Do the MAC */ | ||
397 | gcry_md_reset(mackey); | ||
398 | gcry_md_write(mackey, buf, totallen); | ||
399 | memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32); | ||
400 | |||
401 | free(buf); | ||
402 | buf = NULL; | ||
403 | |||
404 | /* Sign the MAC */ | ||
405 | err = otrl_privkey_sign(&sigbuf, &siglen, privkey, macbuf, 32); | ||
406 | if (err) goto err; | ||
407 | |||
408 | /* Calculate the total size of the structure to be encrypted */ | ||
409 | totallen = 2 + privkey->pubkey_datalen + 4 + siglen; | ||
410 | buf = malloc(totallen); | ||
411 | if (buf == NULL) goto memerr; | ||
412 | bufp = buf; | ||
413 | lenp = totallen; | ||
414 | |||
415 | /* Write the data to be encrypted */ | ||
416 | bufp[0] = ((privkey->pubkey_type) >> 8) & 0xff; | ||
417 | bufp[1] = (privkey->pubkey_type) & 0xff; | ||
418 | bufp += 2; lenp -= 2; | ||
419 | memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen); | ||
420 | debug_data("Pubkey", bufp, privkey->pubkey_datalen); | ||
421 | bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen; | ||
422 | write_int(keyid); | ||
423 | debug_int("Keyid", bufp-4); | ||
424 | memmove(bufp, sigbuf, siglen); | ||
425 | debug_data("Signature", bufp, siglen); | ||
426 | bufp += siglen; lenp -= siglen; | ||
427 | free(sigbuf); | ||
428 | sigbuf = NULL; | ||
429 | |||
430 | assert(lenp == 0); | ||
431 | |||
432 | /* Now do the encryption */ | ||
433 | err = gcry_cipher_encrypt(enckey, buf, totallen, NULL, 0); | ||
434 | if (err) goto err; | ||
435 | |||
436 | *authbufp = buf; | ||
437 | buf = NULL; | ||
438 | *authlenp = totallen; | ||
439 | |||
440 | return err; | ||
441 | memerr: | ||
442 | err = gcry_error(GPG_ERR_ENOMEM); | ||
443 | err: | ||
444 | free(buf); | ||
445 | free(sigbuf); | ||
446 | return err; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * Decrypt the authenticator in the Reveal Signature and Signature | ||
451 | * Messages, given a MAC key, and encryption key, and two DH public | ||
452 | * keys. The fingerprint of the received public key will get put into | ||
453 | * fingerprintbufp, and the received keyid will get put in *keyidp. | ||
454 | * The encrypted data pointed to by authbuf will be decrypted in place. | ||
455 | */ | ||
456 | static gcry_error_t check_pubkey_auth(unsigned char fingerprintbufp[20], | ||
457 | unsigned int *keyidp, unsigned char *authbuf, size_t authlen, | ||
458 | gcry_md_hd_t mackey, gcry_cipher_hd_t enckey, | ||
459 | gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub) | ||
460 | { | ||
461 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
462 | const enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
463 | size_t ourpublen, theirpublen, totallen, lenp; | ||
464 | unsigned char *buf = NULL, *bufp = NULL; | ||
465 | unsigned char macbuf[32]; | ||
466 | unsigned short pubkey_type; | ||
467 | gcry_mpi_t p,q,g,y; | ||
468 | gcry_sexp_t pubs = NULL; | ||
469 | unsigned int received_keyid; | ||
470 | unsigned char *fingerprintstart, *fingerprintend, *sigbuf; | ||
471 | size_t siglen; | ||
472 | |||
473 | /* Start by decrypting it */ | ||
474 | err = gcry_cipher_decrypt(enckey, authbuf, authlen, NULL, 0); | ||
475 | if (err) goto err; | ||
476 | |||
477 | bufp = authbuf; | ||
478 | lenp = authlen; | ||
479 | |||
480 | /* Get the public key and calculate its fingerprint */ | ||
481 | require_len(2); | ||
482 | pubkey_type = (bufp[0] << 8) + bufp[1]; | ||
483 | bufp += 2; lenp -= 2; | ||
484 | if (pubkey_type != OTRL_PUBKEY_TYPE_DSA) goto invval; | ||
485 | fingerprintstart = bufp; | ||
486 | read_mpi(p); | ||
487 | read_mpi(q); | ||
488 | read_mpi(g); | ||
489 | read_mpi(y); | ||
490 | fingerprintend = bufp; | ||
491 | gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbufp, | ||
492 | fingerprintstart, fingerprintend-fingerprintstart); | ||
493 | gcry_sexp_build(&pubs, NULL, | ||
494 | "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y); | ||
495 | gcry_mpi_release(p); | ||
496 | gcry_mpi_release(q); | ||
497 | gcry_mpi_release(g); | ||
498 | gcry_mpi_release(y); | ||
499 | |||
500 | /* Get the keyid */ | ||
501 | read_int(received_keyid); | ||
502 | if (received_keyid == 0) goto invval; | ||
503 | |||
504 | /* Get the signature */ | ||
505 | sigbuf = bufp; | ||
506 | siglen = lenp; | ||
507 | |||
508 | /* How big are the DH public keys? */ | ||
509 | gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub); | ||
510 | gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub); | ||
511 | |||
512 | /* Now calculate the message to be MAC'd. */ | ||
513 | totallen = 4 + ourpublen + 4 + theirpublen + 2 + | ||
514 | (fingerprintend - fingerprintstart) + 4; | ||
515 | buf = malloc(totallen); | ||
516 | if (buf == NULL) goto memerr; | ||
517 | |||
518 | bufp = buf; | ||
519 | lenp = totallen; | ||
520 | |||
521 | write_mpi(their_dh_pub, theirpublen, "Their DH pubkey"); | ||
522 | write_mpi(our_dh_pub, ourpublen, "Our DH pubkey"); | ||
523 | bufp[0] = (pubkey_type >> 8) & 0xff; | ||
524 | bufp[1] = pubkey_type & 0xff; | ||
525 | bufp += 2; lenp -= 2; | ||
526 | memmove(bufp, fingerprintstart, fingerprintend - fingerprintstart); | ||
527 | debug_data("Pubkey", bufp, fingerprintend - fingerprintstart); | ||
528 | bufp += fingerprintend - fingerprintstart; | ||
529 | lenp -= fingerprintend - fingerprintstart; | ||
530 | write_int(received_keyid); | ||
531 | debug_int("Keyid", bufp-4); | ||
532 | |||
533 | assert(lenp == 0); | ||
534 | |||
535 | /* Do the MAC */ | ||
536 | gcry_md_reset(mackey); | ||
537 | gcry_md_write(mackey, buf, totallen); | ||
538 | memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32); | ||
539 | |||
540 | free(buf); | ||
541 | buf = NULL; | ||
542 | |||
543 | /* Verify the signature on the MAC */ | ||
544 | err = otrl_privkey_verify(sigbuf, siglen, pubkey_type, pubs, macbuf, 32); | ||
545 | if (err) goto err; | ||
546 | gcry_sexp_release(pubs); | ||
547 | pubs = NULL; | ||
548 | |||
549 | /* Everything checked out */ | ||
550 | *keyidp = received_keyid; | ||
551 | |||
552 | return err; | ||
553 | invval: | ||
554 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
555 | goto err; | ||
556 | memerr: | ||
557 | err = gcry_error(GPG_ERR_ENOMEM); | ||
558 | err: | ||
559 | free(buf); | ||
560 | gcry_sexp_release(pubs); | ||
561 | return err; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * Create a Reveal Signature Message using the values in the given auth, | ||
566 | * and store it in auth->lastauthmsg. Use the given privkey to sign the | ||
567 | * message. | ||
568 | */ | ||
569 | static gcry_error_t create_revealsig_message(OtrlAuthInfo *auth, | ||
570 | OtrlPrivKey *privkey) | ||
571 | { | ||
572 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
573 | unsigned char *buf = NULL, *bufp, *startmac; | ||
574 | size_t buflen, lenp; | ||
575 | |||
576 | unsigned char *authbuf = NULL; | ||
577 | size_t authlen; | ||
578 | |||
579 | /* Get the encrypted authenticator */ | ||
580 | err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1, auth->enc_c, | ||
581 | auth->our_dh.pub, auth->their_pub, privkey, auth->our_keyid); | ||
582 | if (err) goto err; | ||
583 | |||
584 | buflen = 3 + 4 + 16 + 4 + authlen + 20; | ||
585 | buf = malloc(buflen); | ||
586 | if (buf == NULL) goto memerr; | ||
587 | |||
588 | bufp = buf; | ||
589 | lenp = buflen; | ||
590 | |||
591 | memmove(bufp, "\x00\x02\x11", 3); /* header */ | ||
592 | debug_data("Header", bufp, 3); | ||
593 | bufp += 3; lenp -= 3; | ||
594 | |||
595 | /* r */ | ||
596 | write_int(16); | ||
597 | memmove(bufp, auth->r, 16); | ||
598 | debug_data("r", bufp, 16); | ||
599 | bufp += 16; lenp -= 16; | ||
600 | |||
601 | /* Encrypted authenticator */ | ||
602 | startmac = bufp; | ||
603 | write_int(authlen); | ||
604 | memmove(bufp, authbuf, authlen); | ||
605 | debug_data("auth", bufp, authlen); | ||
606 | bufp += authlen; lenp -= authlen; | ||
607 | free(authbuf); | ||
608 | authbuf = NULL; | ||
609 | |||
610 | /* MAC it, but only take the first 20 bytes */ | ||
611 | gcry_md_reset(auth->mac_m2); | ||
612 | gcry_md_write(auth->mac_m2, startmac, bufp - startmac); | ||
613 | memmove(bufp, gcry_md_read(auth->mac_m2, GCRY_MD_SHA256), 20); | ||
614 | debug_data("MAC", bufp, 20); | ||
615 | bufp += 20; lenp -= 20; | ||
616 | |||
617 | assert(lenp == 0); | ||
618 | |||
619 | free(auth->lastauthmsg); | ||
620 | auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); | ||
621 | if (auth->lastauthmsg == NULL) goto memerr; | ||
622 | free(buf); | ||
623 | buf = NULL; | ||
624 | |||
625 | return err; | ||
626 | |||
627 | memerr: | ||
628 | err = gcry_error(GPG_ERR_ENOMEM); | ||
629 | err: | ||
630 | free(buf); | ||
631 | free(authbuf); | ||
632 | return err; | ||
633 | } | ||
634 | |||
635 | /* | ||
636 | * Create a Signature Message using the values in the given auth, and | ||
637 | * store it in auth->lastauthmsg. Use the given privkey to sign the | ||
638 | * message. | ||
639 | */ | ||
640 | static gcry_error_t create_signature_message(OtrlAuthInfo *auth, | ||
641 | OtrlPrivKey *privkey) | ||
642 | { | ||
643 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
644 | unsigned char *buf = NULL, *bufp, *startmac; | ||
645 | size_t buflen, lenp; | ||
646 | |||
647 | unsigned char *authbuf = NULL; | ||
648 | size_t authlen; | ||
649 | |||
650 | /* Get the encrypted authenticator */ | ||
651 | err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1p, | ||
652 | auth->enc_cp, auth->our_dh.pub, auth->their_pub, privkey, | ||
653 | auth->our_keyid); | ||
654 | if (err) goto err; | ||
655 | |||
656 | buflen = 3 + 4 + authlen + 20; | ||
657 | buf = malloc(buflen); | ||
658 | if (buf == NULL) goto memerr; | ||
659 | |||
660 | bufp = buf; | ||
661 | lenp = buflen; | ||
662 | |||
663 | memmove(bufp, "\x00\x02\x12", 3); /* header */ | ||
664 | debug_data("Header", bufp, 3); | ||
665 | bufp += 3; lenp -= 3; | ||
666 | |||
667 | /* Encrypted authenticator */ | ||
668 | startmac = bufp; | ||
669 | write_int(authlen); | ||
670 | memmove(bufp, authbuf, authlen); | ||
671 | debug_data("auth", bufp, authlen); | ||
672 | bufp += authlen; lenp -= authlen; | ||
673 | free(authbuf); | ||
674 | authbuf = NULL; | ||
675 | |||
676 | /* MAC it, but only take the first 20 bytes */ | ||
677 | gcry_md_reset(auth->mac_m2p); | ||
678 | gcry_md_write(auth->mac_m2p, startmac, bufp - startmac); | ||
679 | memmove(bufp, gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256), 20); | ||
680 | debug_data("MAC", bufp, 20); | ||
681 | bufp += 20; lenp -= 20; | ||
682 | |||
683 | assert(lenp == 0); | ||
684 | |||
685 | free(auth->lastauthmsg); | ||
686 | auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen); | ||
687 | if (auth->lastauthmsg == NULL) goto memerr; | ||
688 | free(buf); | ||
689 | buf = NULL; | ||
690 | |||
691 | return err; | ||
692 | |||
693 | memerr: | ||
694 | err = gcry_error(GPG_ERR_ENOMEM); | ||
695 | err: | ||
696 | free(buf); | ||
697 | free(authbuf); | ||
698 | return err; | ||
699 | } | ||
700 | |||
701 | /* | ||
702 | * Handle an incoming D-H Key Message. If no error is returned, and | ||
703 | * *havemsgp is 1, the message to sent will be left in auth->lastauthmsg. | ||
704 | * Use the given private authentication key to sign messages. | ||
705 | */ | ||
706 | gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg, | ||
707 | int *havemsgp, OtrlPrivKey *privkey) | ||
708 | { | ||
709 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
710 | unsigned char *buf = NULL, *bufp = NULL; | ||
711 | size_t buflen, lenp; | ||
712 | gcry_mpi_t incoming_pub = NULL; | ||
713 | int res; | ||
714 | |||
715 | *havemsgp = 0; | ||
716 | |||
717 | res = otrl_base64_otr_decode(keymsg, &buf, &buflen); | ||
718 | if (res == -1) goto memerr; | ||
719 | if (res == -2) goto invval; | ||
720 | |||
721 | bufp = buf; | ||
722 | lenp = buflen; | ||
723 | |||
724 | /* Header */ | ||
725 | if (memcmp(bufp, "\x00\x02\x0a", 3)) goto invval; | ||
726 | bufp += 3; lenp -= 3; | ||
727 | |||
728 | /* g^y */ | ||
729 | read_mpi(incoming_pub); | ||
730 | |||
731 | if (lenp != 0) goto invval; | ||
732 | free(buf); | ||
733 | buf = NULL; | ||
734 | |||
735 | switch(auth->authstate) { | ||
736 | case OTRL_AUTHSTATE_AWAITING_DHKEY: | ||
737 | /* Store the incoming public key */ | ||
738 | gcry_mpi_release(auth->their_pub); | ||
739 | auth->their_pub = incoming_pub; | ||
740 | incoming_pub = NULL; | ||
741 | |||
742 | /* Compute the encryption and MAC keys */ | ||
743 | err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh), | ||
744 | auth->their_pub, auth->secure_session_id, | ||
745 | &(auth->secure_session_id_len), | ||
746 | &(auth->enc_c), &(auth->enc_cp), | ||
747 | &(auth->mac_m1), &(auth->mac_m1p), | ||
748 | &(auth->mac_m2), &(auth->mac_m2p)); | ||
749 | if (err) goto err; | ||
750 | |||
751 | /* Create the Reveal Signature Message */ | ||
752 | err = create_revealsig_message(auth, privkey); | ||
753 | if (err) goto err; | ||
754 | *havemsgp = 1; | ||
755 | auth->authstate = OTRL_AUTHSTATE_AWAITING_SIG; | ||
756 | |||
757 | break; | ||
758 | |||
759 | case OTRL_AUTHSTATE_AWAITING_SIG: | ||
760 | if (gcry_mpi_cmp(incoming_pub, auth->their_pub) == 0) { | ||
761 | /* Retransmit the Reveal Signature Message */ | ||
762 | *havemsgp = 1; | ||
763 | } else { | ||
764 | /* Ignore this message */ | ||
765 | *havemsgp = 0; | ||
766 | } | ||
767 | break; | ||
768 | case OTRL_AUTHSTATE_NONE: | ||
769 | case OTRL_AUTHSTATE_AWAITING_REVEALSIG: | ||
770 | case OTRL_AUTHSTATE_V1_SETUP: | ||
771 | /* Ignore this message */ | ||
772 | *havemsgp = 0; | ||
773 | break; | ||
774 | } | ||
775 | |||
776 | gcry_mpi_release(incoming_pub); | ||
777 | return err; | ||
778 | |||
779 | invval: | ||
780 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
781 | goto err; | ||
782 | memerr: | ||
783 | err = gcry_error(GPG_ERR_ENOMEM); | ||
784 | err: | ||
785 | free(buf); | ||
786 | gcry_mpi_release(incoming_pub); | ||
787 | return err; | ||
788 | } | ||
789 | |||
790 | /* | ||
791 | * Handle an incoming Reveal Signature Message. If no error is | ||
792 | * returned, and *havemsgp is 1, the message to be sent will be left in | ||
793 | * auth->lastauthmsg. Use the given private authentication key to sign | ||
794 | * messages. Call the auth_succeeded callback if authentication is | ||
795 | * successful. | ||
796 | */ | ||
797 | gcry_error_t otrl_auth_handle_revealsig(OtrlAuthInfo *auth, | ||
798 | const char *revealmsg, int *havemsgp, OtrlPrivKey *privkey, | ||
799 | gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), | ||
800 | void *asdata) | ||
801 | { | ||
802 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
803 | unsigned char *buf = NULL, *bufp = NULL, *gxbuf = NULL; | ||
804 | unsigned char *authstart, *authend, *macstart; | ||
805 | size_t buflen, lenp, rlen, authlen; | ||
806 | gcry_cipher_hd_t enc = NULL; | ||
807 | gcry_mpi_t incoming_pub = NULL; | ||
808 | unsigned char ctr[16], hashbuf[32]; | ||
809 | int res; | ||
810 | |||
811 | *havemsgp = 0; | ||
812 | |||
813 | res = otrl_base64_otr_decode(revealmsg, &buf, &buflen); | ||
814 | if (res == -1) goto memerr; | ||
815 | if (res == -2) goto invval; | ||
816 | |||
817 | bufp = buf; | ||
818 | lenp = buflen; | ||
819 | |||
820 | /* Header */ | ||
821 | if (memcmp(bufp, "\x00\x02\x11", 3)) goto invval; | ||
822 | bufp += 3; lenp -= 3; | ||
823 | |||
824 | /* r */ | ||
825 | read_int(rlen); | ||
826 | if (rlen != 16) goto invval; | ||
827 | require_len(rlen); | ||
828 | memmove(auth->r, bufp, rlen); | ||
829 | bufp += rlen; lenp -= rlen; | ||
830 | |||
831 | /* auth */ | ||
832 | authstart = bufp; | ||
833 | read_int(authlen); | ||
834 | require_len(authlen); | ||
835 | bufp += authlen; lenp -= authlen; | ||
836 | authend = bufp; | ||
837 | |||
838 | /* MAC */ | ||
839 | require_len(20); | ||
840 | macstart = bufp; | ||
841 | bufp += 20; lenp -= 20; | ||
842 | |||
843 | if (lenp != 0) goto invval; | ||
844 | |||
845 | switch(auth->authstate) { | ||
846 | case OTRL_AUTHSTATE_AWAITING_REVEALSIG: | ||
847 | gxbuf = malloc(auth->encgx_len); | ||
848 | if (auth->encgx_len && gxbuf == NULL) goto memerr; | ||
849 | |||
850 | /* Use r to decrypt the value of g^x we received earlier */ | ||
851 | err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, | ||
852 | GCRY_CIPHER_SECURE); | ||
853 | if (err) goto err; | ||
854 | |||
855 | err = gcry_cipher_setkey(enc, auth->r, 16); | ||
856 | if (err) goto err; | ||
857 | |||
858 | memset(ctr, 0, 16); | ||
859 | err = gcry_cipher_setctr(enc, ctr, 16); | ||
860 | if (err) goto err; | ||
861 | |||
862 | err = gcry_cipher_decrypt(enc, gxbuf, auth->encgx_len, | ||
863 | auth->encgx, auth->encgx_len); | ||
864 | if (err) goto err; | ||
865 | |||
866 | gcry_cipher_close(enc); | ||
867 | enc = NULL; | ||
868 | |||
869 | /* Check the hash */ | ||
870 | gcry_md_hash_buffer(GCRY_MD_SHA256, hashbuf, gxbuf, | ||
871 | auth->encgx_len); | ||
872 | if (memcmp(hashbuf, auth->hashgx, 32)) goto decfail; | ||
873 | |||
874 | /* Extract g^x */ | ||
875 | bufp = gxbuf; | ||
876 | lenp = auth->encgx_len; | ||
877 | |||
878 | read_mpi(incoming_pub); | ||
879 | free(gxbuf); | ||
880 | gxbuf = NULL; | ||
881 | |||
882 | if (lenp != 0) goto invval; | ||
883 | |||
884 | gcry_mpi_release(auth->their_pub); | ||
885 | auth->their_pub = incoming_pub; | ||
886 | incoming_pub = NULL; | ||
887 | |||
888 | /* Compute the encryption and MAC keys */ | ||
889 | err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh), | ||
890 | auth->their_pub, auth->secure_session_id, | ||
891 | &(auth->secure_session_id_len), | ||
892 | &(auth->enc_c), &(auth->enc_cp), | ||
893 | &(auth->mac_m1), &(auth->mac_m1p), | ||
894 | &(auth->mac_m2), &(auth->mac_m2p)); | ||
895 | if (err) goto err; | ||
896 | |||
897 | /* Check the MAC */ | ||
898 | gcry_md_reset(auth->mac_m2); | ||
899 | gcry_md_write(auth->mac_m2, authstart, authend - authstart); | ||
900 | if (memcmp(macstart, | ||
901 | gcry_md_read(auth->mac_m2, GCRY_MD_SHA256), | ||
902 | 20)) goto invval; | ||
903 | |||
904 | /* Check the auth */ | ||
905 | err = check_pubkey_auth(auth->their_fingerprint, | ||
906 | &(auth->their_keyid), authstart + 4, | ||
907 | authend - authstart - 4, auth->mac_m1, auth->enc_c, | ||
908 | auth->our_dh.pub, auth->their_pub); | ||
909 | if (err) goto err; | ||
910 | |||
911 | authstart = NULL; | ||
912 | authend = NULL; | ||
913 | macstart = NULL; | ||
914 | free(buf); | ||
915 | buf = NULL; | ||
916 | |||
917 | /* Create the Signature Message */ | ||
918 | err = create_signature_message(auth, privkey); | ||
919 | if (err) goto err; | ||
920 | |||
921 | /* No error? Then we've completed our end of the | ||
922 | * authentication. */ | ||
923 | auth->protocol_version = 2; | ||
924 | auth->session_id_half = OTRL_SESSIONID_SECOND_HALF_BOLD; | ||
925 | if (auth_succeeded) err = auth_succeeded(auth, asdata); | ||
926 | *havemsgp = 1; | ||
927 | auth->our_keyid = 0; | ||
928 | auth->authstate = OTRL_AUTHSTATE_NONE; | ||
929 | |||
930 | break; | ||
931 | case OTRL_AUTHSTATE_NONE: | ||
932 | case OTRL_AUTHSTATE_AWAITING_DHKEY: | ||
933 | case OTRL_AUTHSTATE_AWAITING_SIG: | ||
934 | case OTRL_AUTHSTATE_V1_SETUP: | ||
935 | /* Ignore this message */ | ||
936 | *havemsgp = 0; | ||
937 | free(buf); | ||
938 | buf = NULL; | ||
939 | break; | ||
940 | } | ||
941 | |||
942 | return err; | ||
943 | |||
944 | decfail: | ||
945 | err = gcry_error(GPG_ERR_NO_ERROR); | ||
946 | goto err; | ||
947 | invval: | ||
948 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
949 | goto err; | ||
950 | memerr: | ||
951 | err = gcry_error(GPG_ERR_ENOMEM); | ||
952 | err: | ||
953 | free(buf); | ||
954 | free(gxbuf); | ||
955 | gcry_cipher_close(enc); | ||
956 | gcry_mpi_release(incoming_pub); | ||
957 | return err; | ||
958 | } | ||
959 | |||
960 | /* | ||
961 | * Handle an incoming Signature Message. If no error is returned, and | ||
962 | * *havemsgp is 1, the message to be sent will be left in | ||
963 | * auth->lastauthmsg. Call the auth_succeeded callback if | ||
964 | * authentication is successful. | ||
965 | */ | ||
966 | gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth, | ||
967 | const char *sigmsg, int *havemsgp, | ||
968 | gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), | ||
969 | void *asdata) | ||
970 | { | ||
971 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
972 | unsigned char *buf = NULL, *bufp = NULL; | ||
973 | unsigned char *authstart, *authend, *macstart; | ||
974 | size_t buflen, lenp, authlen; | ||
975 | int res; | ||
976 | |||
977 | *havemsgp = 0; | ||
978 | |||
979 | res = otrl_base64_otr_decode(sigmsg, &buf, &buflen); | ||
980 | if (res == -1) goto memerr; | ||
981 | if (res == -2) goto invval; | ||
982 | |||
983 | bufp = buf; | ||
984 | lenp = buflen; | ||
985 | |||
986 | /* Header */ | ||
987 | if (memcmp(bufp, "\x00\x02\x12", 3)) goto invval; | ||
988 | bufp += 3; lenp -= 3; | ||
989 | |||
990 | /* auth */ | ||
991 | authstart = bufp; | ||
992 | read_int(authlen); | ||
993 | require_len(authlen); | ||
994 | bufp += authlen; lenp -= authlen; | ||
995 | authend = bufp; | ||
996 | |||
997 | /* MAC */ | ||
998 | require_len(20); | ||
999 | macstart = bufp; | ||
1000 | bufp += 20; lenp -= 20; | ||
1001 | |||
1002 | if (lenp != 0) goto invval; | ||
1003 | |||
1004 | switch(auth->authstate) { | ||
1005 | case OTRL_AUTHSTATE_AWAITING_SIG: | ||
1006 | /* Check the MAC */ | ||
1007 | gcry_md_reset(auth->mac_m2p); | ||
1008 | gcry_md_write(auth->mac_m2p, authstart, authend - authstart); | ||
1009 | if (memcmp(macstart, | ||
1010 | gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256), | ||
1011 | 20)) goto invval; | ||
1012 | |||
1013 | /* Check the auth */ | ||
1014 | err = check_pubkey_auth(auth->their_fingerprint, | ||
1015 | &(auth->their_keyid), authstart + 4, | ||
1016 | authend - authstart - 4, auth->mac_m1p, auth->enc_cp, | ||
1017 | auth->our_dh.pub, auth->their_pub); | ||
1018 | if (err) goto err; | ||
1019 | |||
1020 | authstart = NULL; | ||
1021 | authend = NULL; | ||
1022 | macstart = NULL; | ||
1023 | free(buf); | ||
1024 | buf = NULL; | ||
1025 | |||
1026 | /* No error? Then we've completed our end of the | ||
1027 | * authentication. */ | ||
1028 | auth->protocol_version = 2; | ||
1029 | auth->session_id_half = OTRL_SESSIONID_FIRST_HALF_BOLD; | ||
1030 | if (auth_succeeded) err = auth_succeeded(auth, asdata); | ||
1031 | free(auth->lastauthmsg); | ||
1032 | auth->lastauthmsg = NULL; | ||
1033 | *havemsgp = 1; | ||
1034 | auth->our_keyid = 0; | ||
1035 | auth->authstate = OTRL_AUTHSTATE_NONE; | ||
1036 | |||
1037 | break; | ||
1038 | case OTRL_AUTHSTATE_NONE: | ||
1039 | case OTRL_AUTHSTATE_AWAITING_DHKEY: | ||
1040 | case OTRL_AUTHSTATE_AWAITING_REVEALSIG: | ||
1041 | case OTRL_AUTHSTATE_V1_SETUP: | ||
1042 | /* Ignore this message */ | ||
1043 | *havemsgp = 0; | ||
1044 | break; | ||
1045 | } | ||
1046 | |||
1047 | return err; | ||
1048 | |||
1049 | invval: | ||
1050 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
1051 | goto err; | ||
1052 | memerr: | ||
1053 | err = gcry_error(GPG_ERR_ENOMEM); | ||
1054 | err: | ||
1055 | free(buf); | ||
1056 | return err; | ||
1057 | } | ||
1058 | |||
1059 | /* Version 1 routines, for compatibility */ | ||
1060 | |||
1061 | /* | ||
1062 | * Create a verion 1 Key Exchange Message using the values in the given | ||
1063 | * auth, and store it in auth->lastauthmsg. Set the Reply field to the | ||
1064 | * given value, and use the given privkey to sign the message. | ||
1065 | */ | ||
1066 | static gcry_error_t create_v1_key_exchange_message(OtrlAuthInfo *auth, | ||
1067 | unsigned char reply, OtrlPrivKey *privkey) | ||
1068 | { | ||
1069 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
1070 | const enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
1071 | unsigned char *buf = NULL, *bufp = NULL, *sigbuf = NULL; | ||
1072 | size_t lenp, ourpublen, totallen, siglen; | ||
1073 | unsigned char hashbuf[20]; | ||
1074 | |||
1075 | if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA) { | ||
1076 | return gpg_error(GPG_ERR_INV_VALUE); | ||
1077 | } | ||
1078 | |||
1079 | /* How big is the DH public key? */ | ||
1080 | gcry_mpi_print(format, NULL, 0, &ourpublen, auth->our_dh.pub); | ||
1081 | |||
1082 | totallen = 3 + 1 + privkey->pubkey_datalen + 4 + 4 + ourpublen + 40; | ||
1083 | buf = malloc(totallen); | ||
1084 | if (buf == NULL) goto memerr; | ||
1085 | |||
1086 | bufp = buf; | ||
1087 | lenp = totallen; | ||
1088 | |||
1089 | memmove(bufp, "\x00\x01\x0a", 3); /* header */ | ||
1090 | debug_data("Header", bufp, 3); | ||
1091 | bufp += 3; lenp -= 3; | ||
1092 | |||
1093 | bufp[0] = reply; | ||
1094 | debug_data("Reply", bufp, 1); | ||
1095 | bufp += 1; lenp -= 1; | ||
1096 | |||
1097 | memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen); | ||
1098 | debug_data("Pubkey", bufp, privkey->pubkey_datalen); | ||
1099 | bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen; | ||
1100 | |||
1101 | write_int(auth->our_keyid); | ||
1102 | debug_int("Keyid", bufp-4); | ||
1103 | |||
1104 | write_mpi(auth->our_dh.pub, ourpublen, "D-H y"); | ||
1105 | |||
1106 | /* Hash all the data written so far, and sign the hash */ | ||
1107 | gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf); | ||
1108 | |||
1109 | err = otrl_privkey_sign(&sigbuf, &siglen, privkey, hashbuf, 20); | ||
1110 | if (err) goto err; | ||
1111 | |||
1112 | if (siglen != 40) goto invval; | ||
1113 | memmove(bufp, sigbuf, 40); | ||
1114 | debug_data("Signature", bufp, 40); | ||
1115 | bufp += 40; lenp -= 40; | ||
1116 | free(sigbuf); | ||
1117 | sigbuf = NULL; | ||
1118 | |||
1119 | assert(lenp == 0); | ||
1120 | |||
1121 | free(auth->lastauthmsg); | ||
1122 | auth->lastauthmsg = otrl_base64_otr_encode(buf, totallen); | ||
1123 | if (auth->lastauthmsg == NULL) goto memerr; | ||
1124 | free(buf); | ||
1125 | buf = NULL; | ||
1126 | |||
1127 | return err; | ||
1128 | |||
1129 | invval: | ||
1130 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
1131 | goto err; | ||
1132 | memerr: | ||
1133 | err = gcry_error(GPG_ERR_ENOMEM); | ||
1134 | err: | ||
1135 | free(buf); | ||
1136 | free(sigbuf); | ||
1137 | return err; | ||
1138 | } | ||
1139 | |||
1140 | /* | ||
1141 | * Start a fresh AKE (version 1) using the given OtrlAuthInfo. If | ||
1142 | * our_dh is NULL, generate a fresh DH keypair to use. Otherwise, use a | ||
1143 | * copy of the one passed (with the given keyid). Use the given private | ||
1144 | * key to sign the message. If no error is returned, the message to | ||
1145 | * transmit will be contained in auth->lastauthmsg. | ||
1146 | */ | ||
1147 | gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh, | ||
1148 | unsigned int our_keyid, OtrlPrivKey *privkey) | ||
1149 | { | ||
1150 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
1151 | |||
1152 | /* Clear out this OtrlAuthInfo and start over */ | ||
1153 | otrl_auth_clear(auth); | ||
1154 | auth->initiated = 1; | ||
1155 | |||
1156 | /* Import the given DH keypair, or else create a fresh one */ | ||
1157 | if (our_dh) { | ||
1158 | otrl_dh_keypair_copy(&(auth->our_dh), our_dh); | ||
1159 | auth->our_keyid = our_keyid; | ||
1160 | } else { | ||
1161 | otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); | ||
1162 | auth->our_keyid = 1; | ||
1163 | } | ||
1164 | |||
1165 | err = create_v1_key_exchange_message(auth, 0, privkey); | ||
1166 | if (!err) { | ||
1167 | auth->authstate = OTRL_AUTHSTATE_V1_SETUP; | ||
1168 | } | ||
1169 | |||
1170 | return err; | ||
1171 | } | ||
1172 | |||
1173 | /* | ||
1174 | * Handle an incoming v1 Key Exchange Message. If no error is returned, | ||
1175 | * and *havemsgp is 1, the message to be sent will be left in | ||
1176 | * auth->lastauthmsg. Use the given private authentication key to sign | ||
1177 | * messages. Call the auth_secceeded callback if authentication is | ||
1178 | * successful. If non-NULL, use a copy of the given D-H keypair, with | ||
1179 | * the given keyid. | ||
1180 | */ | ||
1181 | gcry_error_t otrl_auth_handle_v1_key_exchange(OtrlAuthInfo *auth, | ||
1182 | const char *keyexchmsg, int *havemsgp, OtrlPrivKey *privkey, | ||
1183 | DH_keypair *our_dh, unsigned int our_keyid, | ||
1184 | gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), | ||
1185 | void *asdata) | ||
1186 | { | ||
1187 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
1188 | unsigned char *buf = NULL, *bufp = NULL; | ||
1189 | unsigned char *fingerprintstart, *fingerprintend; | ||
1190 | unsigned char fingerprintbuf[20], hashbuf[20]; | ||
1191 | gcry_mpi_t p, q, g, y, received_pub = NULL; | ||
1192 | gcry_sexp_t pubs = NULL; | ||
1193 | size_t buflen, lenp; | ||
1194 | unsigned char received_reply; | ||
1195 | unsigned int received_keyid; | ||
1196 | int res; | ||
1197 | |||
1198 | *havemsgp = 0; | ||
1199 | |||
1200 | res = otrl_base64_otr_decode(keyexchmsg, &buf, &buflen); | ||
1201 | if (res == -1) goto memerr; | ||
1202 | if (res == -2) goto invval; | ||
1203 | |||
1204 | bufp = buf; | ||
1205 | lenp = buflen; | ||
1206 | |||
1207 | /* Header */ | ||
1208 | require_len(3); | ||
1209 | if (memcmp(bufp, "\x00\x01\x0a", 3)) goto invval; | ||
1210 | bufp += 3; lenp -= 3; | ||
1211 | |||
1212 | /* Reply */ | ||
1213 | require_len(1); | ||
1214 | received_reply = bufp[0]; | ||
1215 | bufp += 1; lenp -= 1; | ||
1216 | |||
1217 | /* Public Key */ | ||
1218 | fingerprintstart = bufp; | ||
1219 | read_mpi(p); | ||
1220 | read_mpi(q); | ||
1221 | read_mpi(g); | ||
1222 | read_mpi(y); | ||
1223 | fingerprintend = bufp; | ||
1224 | gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbuf, | ||
1225 | fingerprintstart, fingerprintend-fingerprintstart); | ||
1226 | gcry_sexp_build(&pubs, NULL, | ||
1227 | "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y); | ||
1228 | gcry_mpi_release(p); | ||
1229 | gcry_mpi_release(q); | ||
1230 | gcry_mpi_release(g); | ||
1231 | gcry_mpi_release(y); | ||
1232 | |||
1233 | /* keyid */ | ||
1234 | read_int(received_keyid); | ||
1235 | if (received_keyid == 0) goto invval; | ||
1236 | |||
1237 | /* D-H pubkey */ | ||
1238 | read_mpi(received_pub); | ||
1239 | |||
1240 | /* Verify the signature */ | ||
1241 | if (lenp != 40) goto invval; | ||
1242 | gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf); | ||
1243 | err = otrl_privkey_verify(bufp, lenp, OTRL_PUBKEY_TYPE_DSA, | ||
1244 | pubs, hashbuf, 20); | ||
1245 | if (err) goto err; | ||
1246 | gcry_sexp_release(pubs); | ||
1247 | pubs = NULL; | ||
1248 | free(buf); | ||
1249 | buf = NULL; | ||
1250 | |||
1251 | if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP && received_reply == 0x01) { | ||
1252 | /* They're replying to something we never sent. We must be | ||
1253 | * logged in more than once; ignore the message. */ | ||
1254 | err = gpg_error(GPG_ERR_NO_ERROR); | ||
1255 | goto err; | ||
1256 | } | ||
1257 | |||
1258 | if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP) { | ||
1259 | /* Clear the auth and start over */ | ||
1260 | otrl_auth_clear(auth); | ||
1261 | } | ||
1262 | |||
1263 | /* Everything checked out */ | ||
1264 | auth->their_keyid = received_keyid; | ||
1265 | gcry_mpi_release(auth->their_pub); | ||
1266 | auth->their_pub = received_pub; | ||
1267 | received_pub = NULL; | ||
1268 | memmove(auth->their_fingerprint, fingerprintbuf, 20); | ||
1269 | |||
1270 | if (received_reply == 0x01) { | ||
1271 | /* Don't send a reply to this. */ | ||
1272 | *havemsgp = 0; | ||
1273 | } else { | ||
1274 | /* Import the given DH keypair, or else create a fresh one */ | ||
1275 | if (our_dh) { | ||
1276 | otrl_dh_keypair_copy(&(auth->our_dh), our_dh); | ||
1277 | auth->our_keyid = our_keyid; | ||
1278 | } else if (auth->our_keyid == 0) { | ||
1279 | otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh)); | ||
1280 | auth->our_keyid = 1; | ||
1281 | } | ||
1282 | |||
1283 | /* Reply with our own Key Exchange Message */ | ||
1284 | err = create_v1_key_exchange_message(auth, 1, privkey); | ||
1285 | if (err) goto err; | ||
1286 | *havemsgp = 1; | ||
1287 | } | ||
1288 | |||
1289 | /* Compute the session id */ | ||
1290 | err = otrl_dh_compute_v1_session_id(&(auth->our_dh), | ||
1291 | auth->their_pub, auth->secure_session_id, | ||
1292 | &(auth->secure_session_id_len), | ||
1293 | &(auth->session_id_half)); | ||
1294 | if (err) goto err; | ||
1295 | |||
1296 | /* We've completed our end of the authentication */ | ||
1297 | auth->protocol_version = 1; | ||
1298 | if (auth_succeeded) err = auth_succeeded(auth, asdata); | ||
1299 | auth->our_keyid = 0; | ||
1300 | auth->authstate = OTRL_AUTHSTATE_NONE; | ||
1301 | |||
1302 | return err; | ||
1303 | |||
1304 | invval: | ||
1305 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
1306 | goto err; | ||
1307 | memerr: | ||
1308 | err = gcry_error(GPG_ERR_ENOMEM); | ||
1309 | err: | ||
1310 | free(buf); | ||
1311 | gcry_sexp_release(pubs); | ||
1312 | gcry_mpi_release(received_pub); | ||
1313 | return err; | ||
1314 | } | ||
1315 | |||
1316 | #ifdef OTRL_TESTING_AUTH | ||
1317 | #include "mem.h" | ||
1318 | #include "privkey.h" | ||
1319 | |||
1320 | #define CHECK_ERR if (err) { printf("Error: %s\n", gcry_strerror(err)); return 1; } | ||
1321 | |||
1322 | static gcry_error_t starting(const OtrlAuthInfo *auth, void *asdata) | ||
1323 | { | ||
1324 | char *name = asdata; | ||
1325 | |||
1326 | fprintf(stderr, "\nStarting ENCRYPTED mode for %s (v%d).\n", name, auth->protocol_version); | ||
1327 | |||
1328 | fprintf(stderr, "\nour_dh (%d):", auth->our_keyid); | ||
1329 | gcry_mpi_dump(auth->our_dh.pub); | ||
1330 | fprintf(stderr, "\ntheir_pub (%d):", auth->their_keyid); | ||
1331 | gcry_mpi_dump(auth->their_pub); | ||
1332 | |||
1333 | debug_data("\nTheir fingerprint", auth->their_fingerprint, 20); | ||
1334 | debug_data("\nSecure session id", auth->secure_session_id, | ||
1335 | auth->secure_session_id_len); | ||
1336 | fprintf(stderr, "Sessionid half: %d\n\n", auth->session_id_half); | ||
1337 | |||
1338 | return gpg_error(GPG_ERR_NO_ERROR); | ||
1339 | } | ||
1340 | |||
1341 | int main(int argc, char **argv) | ||
1342 | { | ||
1343 | OtrlAuthInfo alice, bob; | ||
1344 | gcry_error_t err; | ||
1345 | int havemsg; | ||
1346 | OtrlUserState us; | ||
1347 | OtrlPrivKey *alicepriv, *bobpriv; | ||
1348 | |||
1349 | otrl_mem_init(); | ||
1350 | otrl_dh_init(); | ||
1351 | otrl_auth_new(&alice); | ||
1352 | otrl_auth_new(&bob); | ||
1353 | |||
1354 | us = otrl_userstate_create(); | ||
1355 | otrl_privkey_read(us, "/home/iang/.gaim/otr.private_key"); | ||
1356 | alicepriv = otrl_privkey_find(us, "oneeyedian", "prpl-oscar"); | ||
1357 | bobpriv = otrl_privkey_find(us, "otr4ian", "prpl-oscar"); | ||
1358 | |||
1359 | printf("\n\n ***** V2 *****\n\n"); | ||
1360 | |||
1361 | err = otrl_auth_start_v2(&bob, NULL, 0); | ||
1362 | CHECK_ERR | ||
1363 | printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); | ||
1364 | err = otrl_auth_handle_commit(&alice, bob.lastauthmsg, NULL, 0); | ||
1365 | CHECK_ERR | ||
1366 | printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg); | ||
1367 | err = otrl_auth_handle_key(&bob, alice.lastauthmsg, &havemsg, bobpriv); | ||
1368 | CHECK_ERR | ||
1369 | if (havemsg) { | ||
1370 | printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); | ||
1371 | } else { | ||
1372 | printf("\nIGNORE\n\n"); | ||
1373 | } | ||
1374 | err = otrl_auth_handle_revealsig(&alice, bob.lastauthmsg, &havemsg, | ||
1375 | alicepriv, starting, "Alice"); | ||
1376 | CHECK_ERR | ||
1377 | if (havemsg) { | ||
1378 | printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg); | ||
1379 | } else { | ||
1380 | printf("\nIGNORE\n\n"); | ||
1381 | } | ||
1382 | err = otrl_auth_handle_signature(&bob, alice.lastauthmsg, &havemsg, | ||
1383 | starting, "Bob"); | ||
1384 | CHECK_ERR | ||
1385 | |||
1386 | printf("\n\n ***** V1 *****\n\n"); | ||
1387 | |||
1388 | err = otrl_auth_start_v1(&bob, NULL, 0, bobpriv); | ||
1389 | CHECK_ERR | ||
1390 | printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); | ||
1391 | err = otrl_auth_handle_v1_key_exchange(&alice, bob.lastauthmsg, | ||
1392 | &havemsg, alicepriv, NULL, 0, starting, "Alice"); | ||
1393 | CHECK_ERR | ||
1394 | if (havemsg) { | ||
1395 | printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg); | ||
1396 | } else { | ||
1397 | printf("\nIGNORE\n\n"); | ||
1398 | } | ||
1399 | err = otrl_auth_handle_v1_key_exchange(&bob, alice.lastauthmsg, | ||
1400 | &havemsg, bobpriv, NULL, 0, starting, "Bob"); | ||
1401 | CHECK_ERR | ||
1402 | if (havemsg) { | ||
1403 | printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg); | ||
1404 | } else { | ||
1405 | printf("\nIGNORE\n\n"); | ||
1406 | } | ||
1407 | |||
1408 | otrl_userstate_free(us); | ||
1409 | otrl_auth_clear(&alice); | ||
1410 | otrl_auth_clear(&bob); | ||
1411 | return 0; | ||
1412 | } | ||
1413 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/auth.h b/linden/indra/libotr/libotr-3.2.0/src/auth.h new file mode 100755 index 0000000..6de75dd --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/auth.h | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __AUTH_H__ | ||
21 | #define __AUTH_H__ | ||
22 | |||
23 | #include <gcrypt.h> | ||
24 | #include "dh.h" | ||
25 | |||
26 | typedef enum { | ||
27 | OTRL_AUTHSTATE_NONE, | ||
28 | OTRL_AUTHSTATE_AWAITING_DHKEY, | ||
29 | OTRL_AUTHSTATE_AWAITING_REVEALSIG, | ||
30 | OTRL_AUTHSTATE_AWAITING_SIG, | ||
31 | OTRL_AUTHSTATE_V1_SETUP | ||
32 | } OtrlAuthState; | ||
33 | |||
34 | typedef struct { | ||
35 | OtrlAuthState authstate; /* Our state */ | ||
36 | |||
37 | DH_keypair our_dh; /* Our D-H key */ | ||
38 | unsigned int our_keyid; /* ...and its keyid */ | ||
39 | |||
40 | unsigned char *encgx; /* The encrypted value of g^x */ | ||
41 | size_t encgx_len; /* ...and its length */ | ||
42 | unsigned char r[16]; /* The encryption key */ | ||
43 | |||
44 | unsigned char hashgx[32]; /* SHA256(g^x) */ | ||
45 | |||
46 | gcry_mpi_t their_pub; /* Their D-H public key */ | ||
47 | unsigned int their_keyid; /* ...and its keyid */ | ||
48 | |||
49 | gcry_cipher_hd_t enc_c, enc_cp; /* c and c' encryption keys */ | ||
50 | gcry_md_hd_t mac_m1, mac_m1p; /* m1 and m1' MAC keys */ | ||
51 | gcry_md_hd_t mac_m2, mac_m2p; /* m2 and m2' MAC keys */ | ||
52 | |||
53 | unsigned char their_fingerprint[20]; /* The fingerprint of their | ||
54 | long-term signing key */ | ||
55 | |||
56 | int initiated; /* Did we initiate this | ||
57 | authentication? */ | ||
58 | |||
59 | unsigned int protocol_version; /* The protocol version number | ||
60 | used to authenticate. */ | ||
61 | |||
62 | unsigned char secure_session_id[20]; /* The secure session id */ | ||
63 | size_t secure_session_id_len; /* And its actual length, | ||
64 | which may be either 20 (for | ||
65 | v1) or 8 (for v2) */ | ||
66 | OtrlSessionIdHalf session_id_half; /* Which half of the session | ||
67 | id gets shown in bold */ | ||
68 | |||
69 | char *lastauthmsg; /* The last auth message | ||
70 | (base-64 encoded) we sent, | ||
71 | in case we need to | ||
72 | retransmit it. */ | ||
73 | } OtrlAuthInfo; | ||
74 | |||
75 | #include "privkey-t.h" | ||
76 | |||
77 | /* | ||
78 | * Initialize the fields of an OtrlAuthInfo (already allocated). | ||
79 | */ | ||
80 | void otrl_auth_new(OtrlAuthInfo *auth); | ||
81 | |||
82 | /* | ||
83 | * Clear the fields of an OtrlAuthInfo (but leave it allocated). | ||
84 | */ | ||
85 | void otrl_auth_clear(OtrlAuthInfo *auth); | ||
86 | |||
87 | /* | ||
88 | * Start a fresh AKE (version 2) using the given OtrlAuthInfo. Generate | ||
89 | * a fresh DH keypair to use. If no error is returned, the message to | ||
90 | * transmit will be contained in auth->lastauthmsg. | ||
91 | */ | ||
92 | gcry_error_t otrl_auth_start_v2(OtrlAuthInfo *auth); | ||
93 | |||
94 | /* | ||
95 | * Handle an incoming D-H Commit Message. If no error is returned, the | ||
96 | * message to send will be left in auth->lastauthmsg. Generate a fresh | ||
97 | * keypair to use. | ||
98 | */ | ||
99 | gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth, | ||
100 | const char *commitmsg); | ||
101 | |||
102 | /* | ||
103 | * Handle an incoming D-H Key Message. If no error is returned, and | ||
104 | * *havemsgp is 1, the message to sent will be left in auth->lastauthmsg. | ||
105 | * Use the given private authentication key to sign messages. | ||
106 | */ | ||
107 | gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg, | ||
108 | int *havemsgp, OtrlPrivKey *privkey); | ||
109 | |||
110 | /* | ||
111 | * Handle an incoming Reveal Signature Message. If no error is | ||
112 | * returned, and *havemsgp is 1, the message to be sent will be left in | ||
113 | * auth->lastauthmsg. Use the given private authentication key to sign | ||
114 | * messages. Call the auth_succeeded callback if authentication is | ||
115 | * successful. | ||
116 | */ | ||
117 | gcry_error_t otrl_auth_handle_revealsig(OtrlAuthInfo *auth, | ||
118 | const char *revealmsg, int *havemsgp, OtrlPrivKey *privkey, | ||
119 | gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), | ||
120 | void *asdata); | ||
121 | |||
122 | /* | ||
123 | * Handle an incoming Signature Message. If no error is returned, and | ||
124 | * *havemsgp is 1, the message to be sent will be left in | ||
125 | * auth->lastauthmsg. Call the auth_succeeded callback if | ||
126 | * authentication is successful. | ||
127 | */ | ||
128 | gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth, | ||
129 | const char *sigmsg, int *havemsgp, | ||
130 | gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), | ||
131 | void *asdata); | ||
132 | |||
133 | /* | ||
134 | * Start a fresh AKE (version 1) using the given OtrlAuthInfo. If | ||
135 | * our_dh is NULL, generate a fresh DH keypair to use. Otherwise, use a | ||
136 | * copy of the one passed (with the given keyid). Use the given private | ||
137 | * key to sign the message. If no error is returned, the message to | ||
138 | * transmit will be contained in auth->lastauthmsg. | ||
139 | */ | ||
140 | gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh, | ||
141 | unsigned int our_keyid, OtrlPrivKey *privkey); | ||
142 | |||
143 | /* | ||
144 | * Handle an incoming v1 Key Exchange Message. If no error is returned, | ||
145 | * and *havemsgp is 1, the message to be sent will be left in | ||
146 | * auth->lastauthmsg. Use the given private authentication key to sign | ||
147 | * messages. Call the auth_secceeded callback if authentication is | ||
148 | * successful. If non-NULL, use a copy of the given D-H keypair, with | ||
149 | * the given keyid. | ||
150 | */ | ||
151 | gcry_error_t otrl_auth_handle_v1_key_exchange(OtrlAuthInfo *auth, | ||
152 | const char *keyexchmsg, int *havemsgp, OtrlPrivKey *privkey, | ||
153 | DH_keypair *our_dh, unsigned int our_keyid, | ||
154 | gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata), | ||
155 | void *asdata); | ||
156 | |||
157 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/b64.c b/linden/indra/libotr/libotr-3.2.0/src/b64.c new file mode 100755 index 0000000..b8736da --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/b64.c | |||
@@ -0,0 +1,249 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* Modified from: */ | ||
21 | |||
22 | /*********************************************************************\ | ||
23 | |||
24 | MODULE NAME: b64.c | ||
25 | |||
26 | AUTHOR: Bob Trower 08/04/01 | ||
27 | |||
28 | LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. | ||
29 | |||
30 | Permission is hereby granted, free of charge, to any person | ||
31 | obtaining a copy of this software and associated | ||
32 | documentation files (the "Software"), to deal in the | ||
33 | Software without restriction, including without limitation | ||
34 | the rights to use, copy, modify, merge, publish, distribute, | ||
35 | sublicense, and/or sell copies of the Software, and to | ||
36 | permit persons to whom the Software is furnished to do so, | ||
37 | subject to the following conditions: | ||
38 | |||
39 | The above copyright notice and this permission notice shall | ||
40 | be included in all copies or substantial portions of the | ||
41 | Software. | ||
42 | |||
43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | ||
44 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | ||
45 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
46 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS | ||
47 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
48 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
49 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
50 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
51 | |||
52 | VERSION HISTORY: | ||
53 | Bob Trower 08/04/01 -- Create Version 0.00.00B | ||
54 | |||
55 | \******************************************************************* */ | ||
56 | |||
57 | /* system headers */ | ||
58 | #include <stdlib.h> | ||
59 | #include <string.h> | ||
60 | |||
61 | /* libotr headers */ | ||
62 | #include "b64.h" | ||
63 | |||
64 | /* | ||
65 | ** Translation Table as described in RFC1113 | ||
66 | */ | ||
67 | static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
68 | |||
69 | /* | ||
70 | ** Translation Table to decode (created by author) | ||
71 | */ | ||
72 | static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; | ||
73 | |||
74 | /* | ||
75 | ** encodeblock | ||
76 | ** | ||
77 | ** encode up to 3 8-bit binary bytes as 4 '6-bit' characters. | ||
78 | ** len must be 1, 2, or 3. | ||
79 | */ | ||
80 | static void encodeblock( char *out, const unsigned char *in, size_t len ) | ||
81 | { | ||
82 | unsigned char in0, in1, in2; | ||
83 | in0 = in[0]; | ||
84 | in1 = len > 1 ? in[1] : 0; | ||
85 | in2 = len > 2 ? in[2] : 0; | ||
86 | |||
87 | out[0] = cb64[ in0 >> 2 ]; | ||
88 | out[1] = cb64[ ((in0 & 0x03) << 4) | ((in1 & 0xf0) >> 4) ]; | ||
89 | out[2] = len > 1 ? cb64[ ((in1 & 0x0f) << 2) | ((in2 & 0xc0) >> 6) ] | ||
90 | : '='; | ||
91 | out[3] = len > 2 ? cb64[ in2 & 0x3f ] | ||
92 | : '='; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * base64 encode data. Insert no linebreaks or whitespace. | ||
97 | * | ||
98 | * The buffer base64data must contain at least ((datalen+2)/3)*4 bytes of | ||
99 | * space. This function will return the number of bytes actually used. | ||
100 | */ | ||
101 | size_t otrl_base64_encode(char *base64data, const unsigned char *data, | ||
102 | size_t datalen) | ||
103 | { | ||
104 | size_t base64len = 0; | ||
105 | |||
106 | while(datalen > 2) { | ||
107 | encodeblock(base64data, data, 3); | ||
108 | base64data += 4; | ||
109 | base64len += 4; | ||
110 | data += 3; | ||
111 | datalen -= 3; | ||
112 | } | ||
113 | if (datalen > 0) { | ||
114 | encodeblock(base64data, data, datalen); | ||
115 | base64len += 4; | ||
116 | } | ||
117 | |||
118 | return base64len; | ||
119 | } | ||
120 | |||
121 | static size_t decode(unsigned char *out, const char *in, size_t b64len) | ||
122 | { | ||
123 | size_t written = 0; | ||
124 | unsigned char c = 0; | ||
125 | |||
126 | if (b64len > 0) { | ||
127 | c = in[0] << 2; | ||
128 | } | ||
129 | if (b64len > 1) { | ||
130 | out[0] = c | in[1] >> 4; | ||
131 | written = 1; | ||
132 | c = in[1] << 4; | ||
133 | } | ||
134 | if (b64len > 2) { | ||
135 | out[1] = c | in[2] >> 2; | ||
136 | written = 2; | ||
137 | c = in[2] << 6; | ||
138 | } | ||
139 | if (b64len > 3) { | ||
140 | out[2] = c | in[3]; | ||
141 | written = 3; | ||
142 | } | ||
143 | return written; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * base64 decode data. Skip non-base64 chars, and terminate at the | ||
148 | * first '=', or the end of the buffer. | ||
149 | * | ||
150 | * The buffer data must contain at least (base64len / 4) * 3 bytes of | ||
151 | * space. This function will return the number of bytes actually used. | ||
152 | */ | ||
153 | size_t otrl_base64_decode(unsigned char *data, const char *base64data, | ||
154 | size_t base64len) | ||
155 | { | ||
156 | size_t datalen = 0; | ||
157 | char b64[4]; | ||
158 | size_t b64accum = 0; | ||
159 | |||
160 | while(base64len > 0) { | ||
161 | char b = *base64data; | ||
162 | unsigned char bdecode; | ||
163 | ++base64data; | ||
164 | --base64len; | ||
165 | if (b < '+' || b > 'z') continue; /* Skip non-base64 chars */ | ||
166 | if (b == '=') { | ||
167 | /* Force termination */ | ||
168 | datalen += decode(data, b64, b64accum); | ||
169 | base64len = 0; | ||
170 | } else { | ||
171 | bdecode = cd64[b-'+']; | ||
172 | if (bdecode == '$') continue; /* Skip non-base64 chars */ | ||
173 | b64[b64accum++] = bdecode-'>'; | ||
174 | if (b64accum == 4) { | ||
175 | /* We have a complete block; decode it. */ | ||
176 | size_t written = decode(data, b64, b64accum); | ||
177 | data += written; | ||
178 | datalen += written; | ||
179 | b64accum = 0; | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* Just discard any short block at the end. */ | ||
185 | |||
186 | return datalen; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Base64-encode a block of data, stick "?OTR:" and "." around it, and | ||
191 | * return the result, or NULL in the event of a memory error. The | ||
192 | * caller must free() the return value. | ||
193 | */ | ||
194 | char *otrl_base64_otr_encode(const unsigned char *buf, size_t buflen) | ||
195 | { | ||
196 | char *base64buf; | ||
197 | size_t base64len; | ||
198 | |||
199 | /* Make the base64-encoding. */ | ||
200 | base64len = ((buflen + 2) / 3) * 4; | ||
201 | base64buf = malloc(5 + base64len + 1 + 1); | ||
202 | if (base64buf == NULL) { | ||
203 | return NULL; | ||
204 | } | ||
205 | memmove(base64buf, "?OTR:", 5); | ||
206 | otrl_base64_encode(base64buf+5, buf, buflen); | ||
207 | base64buf[5 + base64len] = '.'; | ||
208 | base64buf[5 + base64len + 1] = '\0'; | ||
209 | |||
210 | return base64buf; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Base64-decode the portion of the given message between "?OTR:" and | ||
215 | * ".". Set *bufp to the decoded data, and set *lenp to its length. | ||
216 | * The caller must free() the result. Return 0 on success, -1 on a | ||
217 | * memory error, or -2 on invalid input. | ||
218 | */ | ||
219 | int otrl_base64_otr_decode(const char *msg, unsigned char **bufp, | ||
220 | size_t *lenp) | ||
221 | { | ||
222 | char *otrtag, *endtag; | ||
223 | size_t msglen, rawlen; | ||
224 | unsigned char *rawmsg; | ||
225 | |||
226 | otrtag = strstr(msg, "?OTR:"); | ||
227 | if (!otrtag) { | ||
228 | return -2; | ||
229 | } | ||
230 | endtag = strchr(otrtag, '.'); | ||
231 | if (endtag) { | ||
232 | msglen = endtag-otrtag; | ||
233 | } else { | ||
234 | return -2; | ||
235 | } | ||
236 | |||
237 | /* Base64-decode the message */ | ||
238 | rawlen = ((msglen-5) / 4) * 3; /* maximum possible */ | ||
239 | rawmsg = malloc(rawlen); | ||
240 | if (!rawmsg && rawlen > 0) { | ||
241 | return -1; | ||
242 | } | ||
243 | rawlen = otrl_base64_decode(rawmsg, otrtag+5, msglen-5); /* actual size */ | ||
244 | |||
245 | *bufp = rawmsg; | ||
246 | *lenp = rawlen; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/b64.h b/linden/indra/libotr/libotr-3.2.0/src/b64.h new file mode 100755 index 0000000..34ef03f --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/b64.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __B64_H__ | ||
21 | #define __B64_H__ | ||
22 | |||
23 | /* | ||
24 | * base64 encode data. Insert no linebreaks or whitespace. | ||
25 | * | ||
26 | * The buffer base64data must contain at least ((datalen+2)/3)*4 bytes of | ||
27 | * space. This function will return the number of bytes actually used. | ||
28 | */ | ||
29 | size_t otrl_base64_encode(char *base64data, const unsigned char *data, | ||
30 | size_t datalen); | ||
31 | |||
32 | /* | ||
33 | * base64 decode data. Skip non-base64 chars, and terminate at the | ||
34 | * first '=', or the end of the buffer. | ||
35 | * | ||
36 | * The buffer data must contain at least (base64len / 4) * 3 bytes of | ||
37 | * space. This function will return the number of bytes actually used. | ||
38 | */ | ||
39 | size_t otrl_base64_decode(unsigned char *data, const char *base64data, | ||
40 | size_t base64len); | ||
41 | |||
42 | /* | ||
43 | * Base64-encode a block of data, stick "?OTR:" and "." around it, and | ||
44 | * return the result, or NULL in the event of a memory error. | ||
45 | */ | ||
46 | char *otrl_base64_otr_encode(const unsigned char *buf, size_t buflen); | ||
47 | |||
48 | /* | ||
49 | * Base64-decode the portion of the given message between "?OTR:" and | ||
50 | * ".". Set *bufp to the decoded data, and set *lenp to its length. | ||
51 | * The caller must free() the result. Return 0 on success, -1 on a | ||
52 | * memory error, or -2 on invalid input. | ||
53 | */ | ||
54 | int otrl_base64_otr_decode(const char *msg, unsigned char **bufp, | ||
55 | size_t *lenp); | ||
56 | |||
57 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/context.c b/linden/indra/libotr/libotr-3.2.0/src/context.c new file mode 100755 index 0000000..4b2369a --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/context.c | |||
@@ -0,0 +1,321 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* system headers */ | ||
21 | #include <stdlib.h> | ||
22 | #include <assert.h> | ||
23 | |||
24 | /* libgcrypt headers */ | ||
25 | #include <gcrypt.h> | ||
26 | |||
27 | /* libotr headers */ | ||
28 | #include "context.h" | ||
29 | #include "proto.h" | ||
30 | |||
31 | /* Create a new connection context. */ | ||
32 | static ConnContext * new_context(const char * user, const char * accountname, | ||
33 | const char * protocol) | ||
34 | { | ||
35 | ConnContext * context; | ||
36 | OtrlSMState *smstate; | ||
37 | context = malloc(sizeof(*context)); | ||
38 | assert(context != NULL); | ||
39 | context->username = strdup(user); | ||
40 | context->accountname = strdup(accountname); | ||
41 | context->protocol = strdup(protocol); | ||
42 | context->fragments = NULL; | ||
43 | context->fragment_len = 0; | ||
44 | context->fragment_n = 0; | ||
45 | context->fragment_k = 0; | ||
46 | context->msgstate = OTRL_MSGSTATE_PLAINTEXT; | ||
47 | otrl_auth_new(&(context->auth)); | ||
48 | |||
49 | smstate = malloc(sizeof(OtrlSMState)); | ||
50 | assert(smstate != NULL); | ||
51 | otrl_sm_state_new(smstate); | ||
52 | context->smstate = smstate; | ||
53 | |||
54 | context->fingerprint_root.fingerprint = NULL; | ||
55 | context->fingerprint_root.context = context; | ||
56 | context->fingerprint_root.next = NULL; | ||
57 | context->fingerprint_root.tous = NULL; | ||
58 | context->active_fingerprint = NULL; | ||
59 | context->their_keyid = 0; | ||
60 | context->their_y = NULL; | ||
61 | context->their_old_y = NULL; | ||
62 | context->our_keyid = 0; | ||
63 | context->our_dh_key.groupid = 0; | ||
64 | context->our_dh_key.priv = NULL; | ||
65 | context->our_dh_key.pub = NULL; | ||
66 | context->our_old_dh_key.groupid = 0; | ||
67 | context->our_old_dh_key.priv = NULL; | ||
68 | context->our_old_dh_key.pub = NULL; | ||
69 | otrl_dh_session_blank(&(context->sesskeys[0][0])); | ||
70 | otrl_dh_session_blank(&(context->sesskeys[0][1])); | ||
71 | otrl_dh_session_blank(&(context->sesskeys[1][0])); | ||
72 | otrl_dh_session_blank(&(context->sesskeys[1][1])); | ||
73 | memset(context->sessionid, 0, 20); | ||
74 | context->sessionid_len = 0; | ||
75 | context->protocol_version = 0; | ||
76 | context->numsavedkeys = 0; | ||
77 | context->preshared_secret = NULL; | ||
78 | context->preshared_secret_len = 0; | ||
79 | context->saved_mac_keys = NULL; | ||
80 | context->generation = 0; | ||
81 | context->lastsent = 0; | ||
82 | context->lastmessage = NULL; | ||
83 | context->may_retransmit = 0; | ||
84 | context->otr_offer = OFFER_NOT; | ||
85 | context->app_data = NULL; | ||
86 | context->app_data_free = NULL; | ||
87 | context->next = NULL; | ||
88 | return context; | ||
89 | } | ||
90 | |||
91 | /* Look up a connection context by name/account/protocol from the given | ||
92 | * OtrlUserState. If add_if_missing is true, allocate and return a new | ||
93 | * context if one does not currently exist. In that event, call | ||
94 | * add_app_data(data, context) so that app_data and app_data_free can be | ||
95 | * filled in by the application, and set *addedp to 1. */ | ||
96 | ConnContext * otrl_context_find(OtrlUserState us, const char *user, | ||
97 | const char *accountname, const char *protocol, int add_if_missing, | ||
98 | int *addedp, | ||
99 | void (*add_app_data)(void *data, ConnContext *context), void *data) | ||
100 | { | ||
101 | ConnContext ** curp; | ||
102 | int usercmp = 1, acctcmp = 1, protocmp = 1; | ||
103 | if (addedp) *addedp = 0; | ||
104 | if (!user || !accountname || !protocol) return NULL; | ||
105 | for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) { | ||
106 | if ((usercmp = strcmp((*curp)->username, user)) > 0 || | ||
107 | (usercmp == 0 && | ||
108 | (acctcmp = strcmp((*curp)->accountname, accountname)) > 0) || | ||
109 | (usercmp == 0 && acctcmp == 0 && | ||
110 | (protocmp = strcmp((*curp)->protocol, protocol)) >= 0)) | ||
111 | /* We're at the right place in the list. We've either found | ||
112 | * it, or gone too far. */ | ||
113 | break; | ||
114 | } | ||
115 | if (usercmp == 0 && acctcmp == 0 && protocmp == 0) { | ||
116 | /* Found it! */ | ||
117 | return *curp; | ||
118 | } | ||
119 | if (add_if_missing) { | ||
120 | ConnContext *newctx; | ||
121 | if (addedp) *addedp = 1; | ||
122 | newctx = new_context(user, accountname, protocol); | ||
123 | newctx->next = *curp; | ||
124 | if (*curp) { | ||
125 | (*curp)->tous = &(newctx->next); | ||
126 | } | ||
127 | *curp = newctx; | ||
128 | newctx->tous = curp; | ||
129 | if (add_app_data) { | ||
130 | add_app_data(data, *curp); | ||
131 | } | ||
132 | return *curp; | ||
133 | } | ||
134 | return NULL; | ||
135 | } | ||
136 | |||
137 | /* Find a fingerprint in a given context, perhaps adding it if not | ||
138 | * present. */ | ||
139 | Fingerprint *otrl_context_find_fingerprint(ConnContext *context, | ||
140 | unsigned char fingerprint[20], int add_if_missing, int *addedp) | ||
141 | { | ||
142 | Fingerprint *f = context->fingerprint_root.next; | ||
143 | if (addedp) *addedp = 0; | ||
144 | while(f) { | ||
145 | if (!memcmp(f->fingerprint, fingerprint, 20)) return f; | ||
146 | f = f->next; | ||
147 | } | ||
148 | /* Didn't find it. */ | ||
149 | if (add_if_missing) { | ||
150 | if (addedp) *addedp = 1; | ||
151 | f = malloc(sizeof(*f)); | ||
152 | assert(f != NULL); | ||
153 | f->fingerprint = malloc(20); | ||
154 | assert(f->fingerprint != NULL); | ||
155 | memmove(f->fingerprint, fingerprint, 20); | ||
156 | f->context = context; | ||
157 | f->trust = NULL; | ||
158 | f->next = context->fingerprint_root.next; | ||
159 | if (f->next) { | ||
160 | f->next->tous = &(f->next); | ||
161 | } | ||
162 | context->fingerprint_root.next = f; | ||
163 | f->tous = &(context->fingerprint_root.next); | ||
164 | return f; | ||
165 | } | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | /* Set the trust level for a given fingerprint */ | ||
170 | void otrl_context_set_trust(Fingerprint *fprint, const char *trust) | ||
171 | { | ||
172 | if (fprint == NULL) return; | ||
173 | |||
174 | free(fprint->trust); | ||
175 | fprint->trust = trust ? strdup(trust) : NULL; | ||
176 | } | ||
177 | |||
178 | /* Set the preshared secret for a given fingerprint. Note that this | ||
179 | * currently only stores the secret in the ConnContext structure, but | ||
180 | * doesn't yet do anything with it. */ | ||
181 | void otrl_context_set_preshared_secret(ConnContext *context, | ||
182 | const unsigned char *secret, size_t secret_len) | ||
183 | { | ||
184 | free(context->preshared_secret); | ||
185 | context->preshared_secret = NULL; | ||
186 | context->preshared_secret_len = 0; | ||
187 | |||
188 | if (secret_len) { | ||
189 | context->preshared_secret = malloc(secret_len); | ||
190 | if (context->preshared_secret) { | ||
191 | memmove(context->preshared_secret, secret, secret_len); | ||
192 | context->preshared_secret_len = secret_len; | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* Force a context into the OTRL_MSGSTATE_FINISHED state. */ | ||
198 | void otrl_context_force_finished(ConnContext *context) | ||
199 | { | ||
200 | context->msgstate = OTRL_MSGSTATE_FINISHED; | ||
201 | otrl_auth_clear(&(context->auth)); | ||
202 | otrl_free_fragments(context); | ||
203 | context->active_fingerprint = NULL; | ||
204 | context->their_keyid = 0; | ||
205 | gcry_mpi_release(context->their_y); | ||
206 | context->their_y = NULL; | ||
207 | gcry_mpi_release(context->their_old_y); | ||
208 | context->their_old_y = NULL; | ||
209 | context->our_keyid = 0; | ||
210 | otrl_dh_keypair_free(&(context->our_dh_key)); | ||
211 | otrl_dh_keypair_free(&(context->our_old_dh_key)); | ||
212 | otrl_dh_session_free(&(context->sesskeys[0][0])); | ||
213 | otrl_dh_session_free(&(context->sesskeys[0][1])); | ||
214 | otrl_dh_session_free(&(context->sesskeys[1][0])); | ||
215 | otrl_dh_session_free(&(context->sesskeys[1][1])); | ||
216 | memset(context->sessionid, 0, 20); | ||
217 | context->sessionid_len = 0; | ||
218 | free(context->preshared_secret); | ||
219 | context->preshared_secret = NULL; | ||
220 | context->preshared_secret_len = 0; | ||
221 | context->protocol_version = 0; | ||
222 | context->numsavedkeys = 0; | ||
223 | free(context->saved_mac_keys); | ||
224 | context->saved_mac_keys = NULL; | ||
225 | gcry_free(context->lastmessage); | ||
226 | context->lastmessage = NULL; | ||
227 | context->may_retransmit = 0; | ||
228 | otrl_sm_state_free(context->smstate); | ||
229 | } | ||
230 | |||
231 | /* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */ | ||
232 | void otrl_context_force_plaintext(ConnContext *context) | ||
233 | { | ||
234 | /* First clean up everything we'd need to do for the FINISHED state */ | ||
235 | otrl_context_force_finished(context); | ||
236 | |||
237 | /* And just set the state properly */ | ||
238 | context->msgstate = OTRL_MSGSTATE_PLAINTEXT; | ||
239 | } | ||
240 | |||
241 | /* Forget a fingerprint (so long as it's not the active one. If it's a | ||
242 | * fingerprint_root, forget the whole context (as long as | ||
243 | * and_maybe_context is set, and it's PLAINTEXT). Also, if it's not | ||
244 | * the fingerprint_root, but it's the only fingerprint, and we're | ||
245 | * PLAINTEXT, forget the whole context if and_maybe_context is set. */ | ||
246 | void otrl_context_forget_fingerprint(Fingerprint *fprint, | ||
247 | int and_maybe_context) | ||
248 | { | ||
249 | ConnContext *context = fprint->context; | ||
250 | if (fprint == &(context->fingerprint_root)) { | ||
251 | if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT && | ||
252 | and_maybe_context) { | ||
253 | otrl_context_forget(context); | ||
254 | } | ||
255 | } else { | ||
256 | if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT || | ||
257 | context->active_fingerprint != fprint) { | ||
258 | free(fprint->fingerprint); | ||
259 | free(fprint->trust); | ||
260 | *(fprint->tous) = fprint->next; | ||
261 | if (fprint->next) { | ||
262 | fprint->next->tous = fprint->tous; | ||
263 | } | ||
264 | free(fprint); | ||
265 | if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT && | ||
266 | context->fingerprint_root.next == NULL && | ||
267 | and_maybe_context) { | ||
268 | /* We just deleted the only fingerprint. Forget the | ||
269 | * whole thing. */ | ||
270 | otrl_context_forget(context); | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* Forget a whole context, so long as it's PLAINTEXT. */ | ||
277 | void otrl_context_forget(ConnContext *context) | ||
278 | { | ||
279 | if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return; | ||
280 | |||
281 | /* Just to be safe, force to plaintext. This also frees any | ||
282 | * extraneous data lying around. */ | ||
283 | otrl_context_force_plaintext(context); | ||
284 | |||
285 | /* First free all the Fingerprints */ | ||
286 | while(context->fingerprint_root.next) { | ||
287 | otrl_context_forget_fingerprint(context->fingerprint_root.next, 0); | ||
288 | } | ||
289 | /* Now free all the dynamic info here */ | ||
290 | free(context->username); | ||
291 | free(context->accountname); | ||
292 | free(context->protocol); | ||
293 | free(context->smstate); | ||
294 | context->username = NULL; | ||
295 | context->accountname = NULL; | ||
296 | context->protocol = NULL; | ||
297 | context->smstate = NULL; | ||
298 | |||
299 | /* Free the application data, if it exists */ | ||
300 | if (context->app_data && context->app_data_free) { | ||
301 | (context->app_data_free)(context->app_data); | ||
302 | context->app_data = NULL; | ||
303 | } | ||
304 | |||
305 | /* Fix the list linkages */ | ||
306 | *(context->tous) = context->next; | ||
307 | if (context->next) { | ||
308 | context->next->tous = context->tous; | ||
309 | } | ||
310 | |||
311 | free(context); | ||
312 | } | ||
313 | |||
314 | /* Forget all the contexts in a given OtrlUserState. */ | ||
315 | void otrl_context_forget_all(OtrlUserState us) | ||
316 | { | ||
317 | while (us->context_root) { | ||
318 | otrl_context_force_plaintext(us->context_root); | ||
319 | otrl_context_forget(us->context_root); | ||
320 | } | ||
321 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/context.h b/linden/indra/libotr/libotr-3.2.0/src/context.h new file mode 100755 index 0000000..b68bd8d --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/context.h | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __CONTEXT_H__ | ||
21 | #define __CONTEXT_H__ | ||
22 | |||
23 | #include <gcrypt.h> | ||
24 | |||
25 | #include "dh.h" | ||
26 | #include "auth.h" | ||
27 | #include "sm.h" | ||
28 | |||
29 | typedef enum { | ||
30 | OTRL_MSGSTATE_PLAINTEXT, /* Not yet started an encrypted | ||
31 | conversation */ | ||
32 | OTRL_MSGSTATE_ENCRYPTED, /* Currently in an encrypted | ||
33 | conversation */ | ||
34 | OTRL_MSGSTATE_FINISHED /* The remote side has sent us a | ||
35 | notification that he has ended | ||
36 | his end of the encrypted | ||
37 | conversation; prevent any | ||
38 | further messages from being | ||
39 | sent to him. */ | ||
40 | } OtrlMessageState; | ||
41 | |||
42 | typedef struct s_fingerprint { | ||
43 | struct s_fingerprint *next; /* The next fingerprint in the list */ | ||
44 | struct s_fingerprint **tous; /* A pointer to the pointer to us */ | ||
45 | unsigned char *fingerprint; /* The fingerprint, or NULL */ | ||
46 | struct context *context; /* The context to which we belong */ | ||
47 | char *trust; /* The trust level of the fingerprint */ | ||
48 | } Fingerprint; | ||
49 | |||
50 | typedef struct context { | ||
51 | struct context * next; /* Linked list pointer */ | ||
52 | struct context ** tous; /* A pointer to the pointer to us */ | ||
53 | |||
54 | char * username; /* The user this context is for */ | ||
55 | char * accountname; /* The username is relative to | ||
56 | this account... */ | ||
57 | char * protocol; /* ... and this protocol */ | ||
58 | |||
59 | char **fragments; /* The parts of the fragmented message | ||
60 | we've seen so far */ | ||
61 | size_t fragment_len; /* The length of fragment */ | ||
62 | unsigned short fragment_n; /* The total number of fragments | ||
63 | in this message */ | ||
64 | unsigned short fragment_k; /* The highest fragment number | ||
65 | we've seen so far for this | ||
66 | message */ | ||
67 | |||
68 | OtrlMessageState msgstate; /* The state of message disposition | ||
69 | with this user */ | ||
70 | OtrlAuthInfo auth; /* The state of ongoing | ||
71 | authentication with this user */ | ||
72 | |||
73 | Fingerprint fingerprint_root; /* The root of a linked list of | ||
74 | Fingerprints entries */ | ||
75 | Fingerprint *active_fingerprint; /* Which fingerprint is in use now? | ||
76 | A pointer into the above list */ | ||
77 | unsigned int their_keyid; /* current keyid used by other side; | ||
78 | this is set to 0 if we get a | ||
79 | OTRL_TLV_DISCONNECTED message from | ||
80 | them. */ | ||
81 | gcry_mpi_t their_y; /* Y[their_keyid] (their DH pubkey) */ | ||
82 | gcry_mpi_t their_old_y; /* Y[their_keyid-1] (their prev DH | ||
83 | pubkey) */ | ||
84 | unsigned int our_keyid; /* current keyid used by us */ | ||
85 | DH_keypair our_dh_key; /* DH key[our_keyid] */ | ||
86 | DH_keypair our_old_dh_key; /* DH key[our_keyid-1] */ | ||
87 | |||
88 | DH_sesskeys sesskeys[2][2]; /* sesskeys[i][j] are the session keys | ||
89 | derived from DH key[our_keyid-i] | ||
90 | and mpi Y[their_keyid-j] */ | ||
91 | |||
92 | unsigned char sessionid[20]; /* The sessionid and bold half */ | ||
93 | size_t sessionid_len; /* determined when this private */ | ||
94 | OtrlSessionIdHalf sessionid_half; /* connection was established. */ | ||
95 | |||
96 | unsigned int protocol_version; /* The version of OTR in use */ | ||
97 | |||
98 | unsigned char *preshared_secret; /* A secret you share with this | ||
99 | user, in order to do | ||
100 | authentication. */ | ||
101 | size_t preshared_secret_len; /* The length of the above secret. */ | ||
102 | |||
103 | /* saved mac keys to be revealed later */ | ||
104 | unsigned int numsavedkeys; | ||
105 | unsigned char *saved_mac_keys; | ||
106 | |||
107 | /* generation number: increment every time we go private, and never | ||
108 | * reset to 0 (unless we remove the context entirely) */ | ||
109 | unsigned int generation; | ||
110 | |||
111 | time_t lastsent; /* The last time a Data Message was sent */ | ||
112 | char *lastmessage; /* The plaintext of the last Data Message sent */ | ||
113 | int may_retransmit; /* Is the last message eligible for | ||
114 | retransmission? */ | ||
115 | |||
116 | enum { | ||
117 | OFFER_NOT, | ||
118 | OFFER_SENT, | ||
119 | OFFER_REJECTED, | ||
120 | OFFER_ACCEPTED | ||
121 | } otr_offer; /* Has this correspondent repsponded to our | ||
122 | OTR offers? */ | ||
123 | |||
124 | /* Application data to be associated with this context */ | ||
125 | void *app_data; | ||
126 | /* A function to free the above data when we forget this context */ | ||
127 | void (*app_data_free)(void *); | ||
128 | |||
129 | OtrlSMState *smstate; /* The state of the current | ||
130 | socialist millionaires exchange */ | ||
131 | } ConnContext; | ||
132 | |||
133 | #include "userstate.h" | ||
134 | |||
135 | /* Look up a connection context by name/account/protocol from the given | ||
136 | * OtrlUserState. If add_if_missing is true, allocate and return a new | ||
137 | * context if one does not currently exist. In that event, call | ||
138 | * add_app_data(data, context) so that app_data and app_data_free can be | ||
139 | * filled in by the application, and set *addedp to 1. */ | ||
140 | ConnContext * otrl_context_find(OtrlUserState us, const char *user, | ||
141 | const char *accountname, const char *protocol, int add_if_missing, | ||
142 | int *addedp, | ||
143 | void (*add_app_data)(void *data, ConnContext *context), void *data); | ||
144 | |||
145 | /* Find a fingerprint in a given context, perhaps adding it if not | ||
146 | * present. */ | ||
147 | Fingerprint *otrl_context_find_fingerprint(ConnContext *context, | ||
148 | unsigned char fingerprint[20], int add_if_missing, int *addedp); | ||
149 | |||
150 | /* Set the trust level for a given fingerprint */ | ||
151 | void otrl_context_set_trust(Fingerprint *fprint, const char *trust); | ||
152 | |||
153 | /* Set the preshared secret for a given fingerprint. Note that this | ||
154 | * currently only stores the secret in the ConnContext structure, but | ||
155 | * doesn't yet do anything with it. */ | ||
156 | void otrl_context_set_preshared_secret(ConnContext *context, | ||
157 | const unsigned char *secret, size_t secret_len); | ||
158 | |||
159 | /* Force a context into the OTRL_MSGSTATE_FINISHED state. */ | ||
160 | void otrl_context_force_finished(ConnContext *context); | ||
161 | |||
162 | /* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */ | ||
163 | void otrl_context_force_plaintext(ConnContext *context); | ||
164 | |||
165 | /* Forget a fingerprint (so long as it's not the active one. If it's a | ||
166 | * fingerprint_root, forget the whole context (as long as | ||
167 | * and_maybe_context is set, and it's PLAINTEXT). Also, if it's not | ||
168 | * the fingerprint_root, but it's the only fingerprint, and we're | ||
169 | * PLAINTEXT, forget the whole context if and_maybe_context is set. */ | ||
170 | void otrl_context_forget_fingerprint(Fingerprint *fprint, | ||
171 | int and_maybe_context); | ||
172 | |||
173 | /* Forget a whole context, so long as it's PLAINTEXT. */ | ||
174 | void otrl_context_forget(ConnContext *context); | ||
175 | |||
176 | /* Forget all the contexts in a given OtrlUserState. */ | ||
177 | void otrl_context_forget_all(OtrlUserState us); | ||
178 | |||
179 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/dh.c b/linden/indra/libotr/libotr-3.2.0/src/dh.c new file mode 100755 index 0000000..610c84e --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/dh.c | |||
@@ -0,0 +1,466 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* system headers */ | ||
21 | #include <stdlib.h> | ||
22 | |||
23 | /* libgcrypt headers */ | ||
24 | #include <gcrypt.h> | ||
25 | |||
26 | /* libotr headers */ | ||
27 | #include "dh.h" | ||
28 | |||
29 | static const char* DH1536_MODULUS_S = "0x" | ||
30 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" | ||
31 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" | ||
32 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" | ||
33 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" | ||
34 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" | ||
35 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" | ||
36 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" | ||
37 | "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; | ||
38 | static const char *DH1536_GENERATOR_S = "0x02"; | ||
39 | static const int DH1536_MOD_LEN_BITS = 1536; | ||
40 | static const int DH1536_MOD_LEN_BYTES = 192; | ||
41 | |||
42 | static gcry_mpi_t DH1536_MODULUS = NULL; | ||
43 | static gcry_mpi_t DH1536_MODULUS_MINUS_2 = NULL; | ||
44 | static gcry_mpi_t DH1536_GENERATOR = NULL; | ||
45 | |||
46 | /* | ||
47 | * Call this once, at plugin load time. It sets up the modulus and | ||
48 | * generator MPIs. | ||
49 | */ | ||
50 | void otrl_dh_init(void) | ||
51 | { | ||
52 | gcry_mpi_scan(&DH1536_MODULUS, GCRYMPI_FMT_HEX, DH1536_MODULUS_S, 0, NULL); | ||
53 | gcry_mpi_scan(&DH1536_GENERATOR, GCRYMPI_FMT_HEX, DH1536_GENERATOR_S, | ||
54 | 0, NULL); | ||
55 | DH1536_MODULUS_MINUS_2 = gcry_mpi_new(DH1536_MOD_LEN_BITS); | ||
56 | gcry_mpi_sub_ui(DH1536_MODULUS_MINUS_2, DH1536_MODULUS, 2); | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Initialize the fields of a DH keypair. | ||
61 | */ | ||
62 | void otrl_dh_keypair_init(DH_keypair *kp) | ||
63 | { | ||
64 | kp->groupid = 0; | ||
65 | kp->priv = NULL; | ||
66 | kp->pub = NULL; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Copy a DH_keypair. | ||
71 | */ | ||
72 | void otrl_dh_keypair_copy(DH_keypair *dst, const DH_keypair *src) | ||
73 | { | ||
74 | dst->groupid = src->groupid; | ||
75 | dst->priv = gcry_mpi_copy(src->priv); | ||
76 | dst->pub = gcry_mpi_copy(src->pub); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Deallocate the contents of a DH_keypair (but not the DH_keypair | ||
81 | * itself) | ||
82 | */ | ||
83 | void otrl_dh_keypair_free(DH_keypair *kp) | ||
84 | { | ||
85 | gcry_mpi_release(kp->priv); | ||
86 | gcry_mpi_release(kp->pub); | ||
87 | kp->priv = NULL; | ||
88 | kp->pub = NULL; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Generate a DH keypair for a specified group. | ||
93 | */ | ||
94 | gcry_error_t otrl_dh_gen_keypair(unsigned int groupid, DH_keypair *kp) | ||
95 | { | ||
96 | unsigned char *secbuf = NULL; | ||
97 | gcry_mpi_t privkey = NULL; | ||
98 | |||
99 | if (groupid != DH1536_GROUP_ID) { | ||
100 | /* Invalid group id */ | ||
101 | return gcry_error(GPG_ERR_INV_VALUE); | ||
102 | } | ||
103 | |||
104 | /* Generate the secret key: a random 320-bit value */ | ||
105 | secbuf = gcry_random_bytes_secure(40, GCRY_STRONG_RANDOM); | ||
106 | gcry_mpi_scan(&privkey, GCRYMPI_FMT_USG, secbuf, 40, NULL); | ||
107 | gcry_free(secbuf); | ||
108 | |||
109 | kp->groupid = groupid; | ||
110 | kp->priv = privkey; | ||
111 | kp->pub = gcry_mpi_new(DH1536_MOD_LEN_BITS); | ||
112 | gcry_mpi_powm(kp->pub, DH1536_GENERATOR, privkey, DH1536_MODULUS); | ||
113 | return gcry_error(GPG_ERR_NO_ERROR); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Construct session keys from a DH keypair and someone else's public | ||
118 | * key. | ||
119 | */ | ||
120 | gcry_error_t otrl_dh_session(DH_sesskeys *sess, const DH_keypair *kp, | ||
121 | gcry_mpi_t y) | ||
122 | { | ||
123 | gcry_mpi_t gab; | ||
124 | size_t gablen; | ||
125 | unsigned char *gabdata; | ||
126 | unsigned char *hashdata; | ||
127 | unsigned char sendbyte, rcvbyte; | ||
128 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
129 | |||
130 | otrl_dh_session_blank(sess); | ||
131 | |||
132 | if (kp->groupid != DH1536_GROUP_ID) { | ||
133 | /* Invalid group id */ | ||
134 | return gcry_error(GPG_ERR_INV_VALUE); | ||
135 | } | ||
136 | |||
137 | /* Calculate the shared secret MPI */ | ||
138 | gab = gcry_mpi_new(DH1536_MOD_LEN_BITS); | ||
139 | gcry_mpi_powm(gab, y, kp->priv, DH1536_MODULUS); | ||
140 | |||
141 | /* Output it in the right format */ | ||
142 | gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &gablen, gab); | ||
143 | gabdata = gcry_malloc_secure(gablen + 5); | ||
144 | if (!gabdata) { | ||
145 | gcry_mpi_release(gab); | ||
146 | return gcry_error(GPG_ERR_ENOMEM); | ||
147 | } | ||
148 | gabdata[1] = (gablen >> 24) & 0xff; | ||
149 | gabdata[2] = (gablen >> 16) & 0xff; | ||
150 | gabdata[3] = (gablen >> 8) & 0xff; | ||
151 | gabdata[4] = gablen & 0xff; | ||
152 | gcry_mpi_print(GCRYMPI_FMT_USG, gabdata+5, gablen, NULL, gab); | ||
153 | gcry_mpi_release(gab); | ||
154 | |||
155 | hashdata = gcry_malloc_secure(20); | ||
156 | if (!hashdata) { | ||
157 | gcry_free(gabdata); | ||
158 | return gcry_error(GPG_ERR_ENOMEM); | ||
159 | } | ||
160 | |||
161 | /* Are we the "high" or "low" end of the connection? */ | ||
162 | if ( gcry_mpi_cmp(kp->pub, y) > 0 ) { | ||
163 | sendbyte = 0x01; | ||
164 | rcvbyte = 0x02; | ||
165 | } else { | ||
166 | sendbyte = 0x02; | ||
167 | rcvbyte = 0x01; | ||
168 | } | ||
169 | |||
170 | /* Calculate the sending encryption key */ | ||
171 | gabdata[0] = sendbyte; | ||
172 | gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5); | ||
173 | err = gcry_cipher_open(&(sess->sendenc), GCRY_CIPHER_AES, | ||
174 | GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); | ||
175 | if (err) goto err; | ||
176 | err = gcry_cipher_setkey(sess->sendenc, hashdata, 16); | ||
177 | if (err) goto err; | ||
178 | |||
179 | /* Calculate the sending MAC key */ | ||
180 | gcry_md_hash_buffer(GCRY_MD_SHA1, sess->sendmackey, hashdata, 16); | ||
181 | err = gcry_md_open(&(sess->sendmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); | ||
182 | if (err) goto err; | ||
183 | err = gcry_md_setkey(sess->sendmac, sess->sendmackey, 20); | ||
184 | if (err) goto err; | ||
185 | |||
186 | /* Calculate the receiving encryption key */ | ||
187 | gabdata[0] = rcvbyte; | ||
188 | gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5); | ||
189 | err = gcry_cipher_open(&(sess->rcvenc), GCRY_CIPHER_AES, | ||
190 | GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); | ||
191 | if (err) goto err; | ||
192 | err = gcry_cipher_setkey(sess->rcvenc, hashdata, 16); | ||
193 | if (err) goto err; | ||
194 | |||
195 | /* Calculate the receiving MAC key (and save it in the DH_sesskeys | ||
196 | * struct, so we can reveal it later) */ | ||
197 | gcry_md_hash_buffer(GCRY_MD_SHA1, sess->rcvmackey, hashdata, 16); | ||
198 | err = gcry_md_open(&(sess->rcvmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); | ||
199 | if (err) goto err; | ||
200 | err = gcry_md_setkey(sess->rcvmac, sess->rcvmackey, 20); | ||
201 | if (err) goto err; | ||
202 | |||
203 | gcry_free(gabdata); | ||
204 | gcry_free(hashdata); | ||
205 | return gcry_error(GPG_ERR_NO_ERROR); | ||
206 | err: | ||
207 | otrl_dh_session_free(sess); | ||
208 | gcry_free(gabdata); | ||
209 | gcry_free(hashdata); | ||
210 | return err; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Compute the secure session id, two encryption keys, and four MAC keys | ||
215 | * given our DH key and their DH public key. | ||
216 | */ | ||
217 | gcry_error_t otrl_dh_compute_v2_auth_keys(const DH_keypair *our_dh, | ||
218 | gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, | ||
219 | gcry_cipher_hd_t *enc_c, gcry_cipher_hd_t *enc_cp, | ||
220 | gcry_md_hd_t *mac_m1, gcry_md_hd_t *mac_m1p, | ||
221 | gcry_md_hd_t *mac_m2, gcry_md_hd_t *mac_m2p) | ||
222 | { | ||
223 | gcry_mpi_t s; | ||
224 | size_t slen; | ||
225 | unsigned char *sdata; | ||
226 | unsigned char *hashdata; | ||
227 | unsigned char ctr[16]; | ||
228 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
229 | |||
230 | *enc_c = NULL; | ||
231 | *enc_cp = NULL; | ||
232 | *mac_m1 = NULL; | ||
233 | *mac_m1p = NULL; | ||
234 | *mac_m2 = NULL; | ||
235 | *mac_m2p = NULL; | ||
236 | memset(ctr, 0, 16); | ||
237 | |||
238 | if (our_dh->groupid != DH1536_GROUP_ID) { | ||
239 | /* Invalid group id */ | ||
240 | return gcry_error(GPG_ERR_INV_VALUE); | ||
241 | } | ||
242 | |||
243 | /* Check that their_pub is in range */ | ||
244 | if (gcry_mpi_cmp_ui(their_pub, 2) < 0 || | ||
245 | gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) { | ||
246 | /* Invalid pubkey */ | ||
247 | return gcry_error(GPG_ERR_INV_VALUE); | ||
248 | } | ||
249 | |||
250 | /* Calculate the shared secret MPI */ | ||
251 | s = gcry_mpi_new(DH1536_MOD_LEN_BITS); | ||
252 | gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS); | ||
253 | |||
254 | /* Output it in the right format */ | ||
255 | gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s); | ||
256 | sdata = gcry_malloc_secure(slen + 5); | ||
257 | if (!sdata) { | ||
258 | gcry_mpi_release(s); | ||
259 | return gcry_error(GPG_ERR_ENOMEM); | ||
260 | } | ||
261 | sdata[1] = (slen >> 24) & 0xff; | ||
262 | sdata[2] = (slen >> 16) & 0xff; | ||
263 | sdata[3] = (slen >> 8) & 0xff; | ||
264 | sdata[4] = slen & 0xff; | ||
265 | gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s); | ||
266 | gcry_mpi_release(s); | ||
267 | |||
268 | /* Calculate the session id */ | ||
269 | hashdata = gcry_malloc_secure(32); | ||
270 | if (!hashdata) { | ||
271 | gcry_free(sdata); | ||
272 | return gcry_error(GPG_ERR_ENOMEM); | ||
273 | } | ||
274 | sdata[0] = 0x00; | ||
275 | gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); | ||
276 | memmove(sessionid, hashdata, 8); | ||
277 | *sessionidlenp = 8; | ||
278 | |||
279 | /* Calculate the encryption keys */ | ||
280 | sdata[0] = 0x01; | ||
281 | gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); | ||
282 | |||
283 | err = gcry_cipher_open(enc_c, GCRY_CIPHER_AES, | ||
284 | GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); | ||
285 | if (err) goto err; | ||
286 | err = gcry_cipher_setkey(*enc_c, hashdata, 16); | ||
287 | if (err) goto err; | ||
288 | err = gcry_cipher_setctr(*enc_c, ctr, 16); | ||
289 | if (err) goto err; | ||
290 | |||
291 | err = gcry_cipher_open(enc_cp, GCRY_CIPHER_AES, | ||
292 | GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE); | ||
293 | if (err) goto err; | ||
294 | err = gcry_cipher_setkey(*enc_cp, hashdata+16, 16); | ||
295 | if (err) goto err; | ||
296 | err = gcry_cipher_setctr(*enc_cp, ctr, 16); | ||
297 | if (err) goto err; | ||
298 | |||
299 | /* Calculate the MAC keys */ | ||
300 | sdata[0] = 0x02; | ||
301 | gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); | ||
302 | err = gcry_md_open(mac_m1, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); | ||
303 | if (err) goto err; | ||
304 | err = gcry_md_setkey(*mac_m1, hashdata, 32); | ||
305 | if (err) goto err; | ||
306 | |||
307 | sdata[0] = 0x03; | ||
308 | gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); | ||
309 | err = gcry_md_open(mac_m2, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); | ||
310 | if (err) goto err; | ||
311 | err = gcry_md_setkey(*mac_m2, hashdata, 32); | ||
312 | if (err) goto err; | ||
313 | |||
314 | sdata[0] = 0x04; | ||
315 | gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); | ||
316 | err = gcry_md_open(mac_m1p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); | ||
317 | if (err) goto err; | ||
318 | err = gcry_md_setkey(*mac_m1p, hashdata, 32); | ||
319 | if (err) goto err; | ||
320 | |||
321 | sdata[0] = 0x05; | ||
322 | gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5); | ||
323 | err = gcry_md_open(mac_m2p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); | ||
324 | if (err) goto err; | ||
325 | err = gcry_md_setkey(*mac_m2p, hashdata, 32); | ||
326 | if (err) goto err; | ||
327 | |||
328 | gcry_free(sdata); | ||
329 | gcry_free(hashdata); | ||
330 | return gcry_error(GPG_ERR_NO_ERROR); | ||
331 | |||
332 | err: | ||
333 | gcry_cipher_close(*enc_c); | ||
334 | gcry_cipher_close(*enc_cp); | ||
335 | gcry_md_close(*mac_m1); | ||
336 | gcry_md_close(*mac_m1p); | ||
337 | gcry_md_close(*mac_m2); | ||
338 | gcry_md_close(*mac_m2p); | ||
339 | *enc_c = NULL; | ||
340 | *enc_cp = NULL; | ||
341 | *mac_m1 = NULL; | ||
342 | *mac_m1p = NULL; | ||
343 | *mac_m2 = NULL; | ||
344 | *mac_m2p = NULL; | ||
345 | gcry_free(sdata); | ||
346 | gcry_free(hashdata); | ||
347 | return err; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * Compute the secure session id, given our DH key and their DH public | ||
352 | * key. | ||
353 | */ | ||
354 | gcry_error_t otrl_dh_compute_v1_session_id(const DH_keypair *our_dh, | ||
355 | gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, | ||
356 | OtrlSessionIdHalf *halfp) | ||
357 | { | ||
358 | gcry_mpi_t s; | ||
359 | size_t slen; | ||
360 | unsigned char *sdata; | ||
361 | unsigned char *hashdata; | ||
362 | |||
363 | if (our_dh->groupid != DH1536_GROUP_ID) { | ||
364 | /* Invalid group id */ | ||
365 | return gcry_error(GPG_ERR_INV_VALUE); | ||
366 | } | ||
367 | |||
368 | /* Check that their_pub is in range */ | ||
369 | if (gcry_mpi_cmp_ui(their_pub, 2) < 0 || | ||
370 | gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) { | ||
371 | /* Invalid pubkey */ | ||
372 | return gcry_error(GPG_ERR_INV_VALUE); | ||
373 | } | ||
374 | |||
375 | /* Calculate the shared secret MPI */ | ||
376 | s = gcry_mpi_new(DH1536_MOD_LEN_BITS); | ||
377 | gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS); | ||
378 | |||
379 | /* Output it in the right format */ | ||
380 | gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s); | ||
381 | sdata = gcry_malloc_secure(slen + 5); | ||
382 | if (!sdata) { | ||
383 | gcry_mpi_release(s); | ||
384 | return gcry_error(GPG_ERR_ENOMEM); | ||
385 | } | ||
386 | sdata[1] = (slen >> 24) & 0xff; | ||
387 | sdata[2] = (slen >> 16) & 0xff; | ||
388 | sdata[3] = (slen >> 8) & 0xff; | ||
389 | sdata[4] = slen & 0xff; | ||
390 | gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s); | ||
391 | gcry_mpi_release(s); | ||
392 | |||
393 | /* Calculate the session id */ | ||
394 | hashdata = gcry_malloc_secure(20); | ||
395 | if (!hashdata) { | ||
396 | gcry_free(sdata); | ||
397 | return gcry_error(GPG_ERR_ENOMEM); | ||
398 | } | ||
399 | sdata[0] = 0x00; | ||
400 | gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, sdata, slen+5); | ||
401 | memmove(sessionid, hashdata, 20); | ||
402 | *sessionidlenp = 20; | ||
403 | |||
404 | /* Which half should be bold? */ | ||
405 | if (gcry_mpi_cmp(our_dh->pub, their_pub) > 0) { | ||
406 | *halfp = OTRL_SESSIONID_SECOND_HALF_BOLD; | ||
407 | } else { | ||
408 | *halfp = OTRL_SESSIONID_FIRST_HALF_BOLD; | ||
409 | } | ||
410 | |||
411 | gcry_free(hashdata); | ||
412 | gcry_free(sdata); | ||
413 | return gcry_error(GPG_ERR_NO_ERROR); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * Deallocate the contents of a DH_sesskeys (but not the DH_sesskeys | ||
418 | * itself) | ||
419 | */ | ||
420 | void otrl_dh_session_free(DH_sesskeys *sess) | ||
421 | { | ||
422 | gcry_cipher_close(sess->sendenc); | ||
423 | gcry_cipher_close(sess->rcvenc); | ||
424 | gcry_md_close(sess->sendmac); | ||
425 | gcry_md_close(sess->rcvmac); | ||
426 | |||
427 | otrl_dh_session_blank(sess); | ||
428 | } | ||
429 | |||
430 | /* | ||
431 | * Blank out the contents of a DH_sesskeys (without releasing it) | ||
432 | */ | ||
433 | void otrl_dh_session_blank(DH_sesskeys *sess) | ||
434 | { | ||
435 | sess->sendenc = NULL; | ||
436 | sess->sendmac = NULL; | ||
437 | sess->rcvenc = NULL; | ||
438 | sess->rcvmac = NULL; | ||
439 | memset(sess->sendctr, 0, 16); | ||
440 | memset(sess->rcvctr, 0, 16); | ||
441 | memset(sess->sendmackey, 0, 20); | ||
442 | memset(sess->rcvmackey, 0, 20); | ||
443 | sess->sendmacused = 0; | ||
444 | sess->rcvmacused = 0; | ||
445 | } | ||
446 | |||
447 | /* Increment the top half of a counter block */ | ||
448 | void otrl_dh_incctr(unsigned char *ctr) | ||
449 | { | ||
450 | int i; | ||
451 | for (i=8;i;--i) { | ||
452 | if (++ctr[i-1]) break; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | /* Compare two counter values (8 bytes each). Return 0 if ctr1 == ctr2, | ||
457 | * < 0 if ctr1 < ctr2 (as unsigned 64-bit values), > 0 if ctr1 > ctr2. */ | ||
458 | int otrl_dh_cmpctr(const unsigned char *ctr1, const unsigned char *ctr2) | ||
459 | { | ||
460 | int i; | ||
461 | for (i=0;i<8;++i) { | ||
462 | int c = ctr1[i] - ctr2[i]; | ||
463 | if (c) return c; | ||
464 | } | ||
465 | return 0; | ||
466 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/dh.h b/linden/indra/libotr/libotr-3.2.0/src/dh.h new file mode 100755 index 0000000..d68328f --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/dh.h | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __DH_H__ | ||
21 | #define __DH_H__ | ||
22 | |||
23 | #define DH1536_GROUP_ID 5 | ||
24 | |||
25 | typedef struct { | ||
26 | unsigned int groupid; | ||
27 | gcry_mpi_t priv, pub; | ||
28 | } DH_keypair; | ||
29 | |||
30 | /* Which half of the secure session id should be shown in bold? */ | ||
31 | typedef enum { | ||
32 | OTRL_SESSIONID_FIRST_HALF_BOLD, | ||
33 | OTRL_SESSIONID_SECOND_HALF_BOLD | ||
34 | } OtrlSessionIdHalf; | ||
35 | |||
36 | typedef struct { | ||
37 | unsigned char sendctr[16]; | ||
38 | unsigned char rcvctr[16]; | ||
39 | gcry_cipher_hd_t sendenc; | ||
40 | gcry_cipher_hd_t rcvenc; | ||
41 | gcry_md_hd_t sendmac; | ||
42 | unsigned char sendmackey[20]; | ||
43 | int sendmacused; | ||
44 | gcry_md_hd_t rcvmac; | ||
45 | unsigned char rcvmackey[20]; | ||
46 | int rcvmacused; | ||
47 | } DH_sesskeys; | ||
48 | |||
49 | /* | ||
50 | * Call this once, at plugin load time. It sets up the modulus and | ||
51 | * generator MPIs. | ||
52 | */ | ||
53 | void otrl_dh_init(void); | ||
54 | |||
55 | /* | ||
56 | * Initialize the fields of a DH keypair. | ||
57 | */ | ||
58 | void otrl_dh_keypair_init(DH_keypair *kp); | ||
59 | |||
60 | /* | ||
61 | * Copy a DH_keypair. | ||
62 | */ | ||
63 | void otrl_dh_keypair_copy(DH_keypair *dst, const DH_keypair *src); | ||
64 | |||
65 | /* | ||
66 | * Deallocate the contents of a DH_keypair (but not the DH_keypair | ||
67 | * itself) | ||
68 | */ | ||
69 | void otrl_dh_keypair_free(DH_keypair *kp); | ||
70 | |||
71 | /* | ||
72 | * Generate a DH keypair for a specified group. | ||
73 | */ | ||
74 | gcry_error_t otrl_dh_gen_keypair(unsigned int groupid, DH_keypair *kp); | ||
75 | |||
76 | /* | ||
77 | * Construct session keys from a DH keypair and someone else's public | ||
78 | * key. | ||
79 | */ | ||
80 | gcry_error_t otrl_dh_session(DH_sesskeys *sess, const DH_keypair *kp, | ||
81 | gcry_mpi_t y); | ||
82 | |||
83 | /* | ||
84 | * Compute the secure session id, two encryption keys, and four MAC keys | ||
85 | * given our DH key and their DH public key. | ||
86 | */ | ||
87 | gcry_error_t otrl_dh_compute_v2_auth_keys(const DH_keypair *our_dh, | ||
88 | gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, | ||
89 | gcry_cipher_hd_t *enc_c, gcry_cipher_hd_t *enc_cp, | ||
90 | gcry_md_hd_t *mac_m1, gcry_md_hd_t *mac_m1p, | ||
91 | gcry_md_hd_t *mac_m2, gcry_md_hd_t *mac_m2p); | ||
92 | |||
93 | /* | ||
94 | * Compute the secure session id, given our DH key and their DH public | ||
95 | * key. | ||
96 | */ | ||
97 | gcry_error_t otrl_dh_compute_v1_session_id(const DH_keypair *our_dh, | ||
98 | gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp, | ||
99 | OtrlSessionIdHalf *halfp); | ||
100 | |||
101 | /* | ||
102 | * Deallocate the contents of a DH_sesskeys (but not the DH_sesskeys | ||
103 | * itself) | ||
104 | */ | ||
105 | void otrl_dh_session_free(DH_sesskeys *sess); | ||
106 | |||
107 | /* | ||
108 | * Blank out the contents of a DH_sesskeys (without releasing it) | ||
109 | */ | ||
110 | void otrl_dh_session_blank(DH_sesskeys *sess); | ||
111 | |||
112 | /* Increment the top half of a counter block */ | ||
113 | void otrl_dh_incctr(unsigned char *ctr); | ||
114 | |||
115 | /* Compare two counter values (8 bytes each). Return 0 if ctr1 == ctr2, | ||
116 | * < 0 if ctr1 < ctr2 (as unsigned 64-bit values), > 0 if ctr1 > ctr2. */ | ||
117 | int otrl_dh_cmpctr(const unsigned char *ctr1, const unsigned char *ctr2); | ||
118 | |||
119 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/mem.c b/linden/indra/libotr/libotr-3.2.0/src/mem.c new file mode 100755 index 0000000..b2a2191 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/mem.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* Memory allocation routines for libgcrypt. All of the session key | ||
21 | * information gets allocated through here, so we can wipe it out when | ||
22 | * it's free()d. We don't use the built-in secmem functions of | ||
23 | * libgcrypt because you need to declare a fixed amount of it when you | ||
24 | * start up. | ||
25 | * | ||
26 | * Because "secure" and "insecure" allocations from libgcrypt will get | ||
27 | * handled the same way (since we're not going to be running as root, | ||
28 | * and so won't actually have pinned memory), pretend all allocated | ||
29 | * memory (but just from libgcrypt) is requested secure, and wipe it on | ||
30 | * free(). */ | ||
31 | |||
32 | /* Uncomment the following to add a check that our free() and realloc() only | ||
33 | * get called on things returned from our malloc(). */ | ||
34 | /* #define OTRL_MEM_MAGIC 0x31415926 */ | ||
35 | |||
36 | /* system headers */ | ||
37 | #ifdef OTRL_MEM_MAGIC | ||
38 | #include <stdio.h> | ||
39 | #endif | ||
40 | #include <stdlib.h> | ||
41 | |||
42 | /* libgcrypt headers */ | ||
43 | #include <gcrypt.h> | ||
44 | |||
45 | /* libotr headers */ | ||
46 | #include "mem.h" | ||
47 | |||
48 | static int header_size; | ||
49 | |||
50 | static void *otrl_mem_malloc(size_t n) | ||
51 | { | ||
52 | void *p; | ||
53 | size_t new_n = n; | ||
54 | new_n += header_size; | ||
55 | |||
56 | /* Check for overflow attack */ | ||
57 | if (new_n < n) return NULL; | ||
58 | p = malloc(new_n); | ||
59 | if (p == NULL) return NULL; | ||
60 | |||
61 | ((size_t *)p)[0] = new_n; /* Includes header size */ | ||
62 | #ifdef OTRL_MEM_MAGIC | ||
63 | ((size_t *)p)[1] = OTRL_MEM_MAGIC; | ||
64 | #endif | ||
65 | |||
66 | return (void *)((char *)p + header_size); | ||
67 | } | ||
68 | |||
69 | static int otrl_mem_is_secure(const void *p) | ||
70 | { | ||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | static void otrl_mem_free(void *p) | ||
75 | { | ||
76 | void *real_p = (void *)((char *)p - header_size); | ||
77 | size_t n = ((size_t *)real_p)[0]; | ||
78 | #ifdef OTRL_MEM_MAGIC | ||
79 | if (((size_t *)real_p)[1] != OTRL_MEM_MAGIC) { | ||
80 | fprintf(stderr, "Illegal free!\n"); | ||
81 | return; | ||
82 | } | ||
83 | #endif | ||
84 | |||
85 | /* Wipe the memory (in the same way the built-in deallocator in | ||
86 | * libgcrypt would) */ | ||
87 | memset(real_p, 0xff, n); | ||
88 | memset(real_p, 0xaa, n); | ||
89 | memset(real_p, 0x55, n); | ||
90 | memset(real_p, 0x00, n); | ||
91 | |||
92 | free(real_p); | ||
93 | } | ||
94 | |||
95 | static void *otrl_mem_realloc(void *p, size_t n) | ||
96 | { | ||
97 | if (p == NULL) { | ||
98 | return otrl_mem_malloc(n); | ||
99 | } else if (n == 0) { | ||
100 | otrl_mem_free(p); | ||
101 | return NULL; | ||
102 | } else { | ||
103 | void *real_p = (void *)((char *)p - header_size); | ||
104 | void *new_p; | ||
105 | size_t old_n = ((size_t *)real_p)[0]; | ||
106 | #ifdef OTRL_MEM_MAGIC | ||
107 | size_t magic = ((size_t *)real_p)[1]; | ||
108 | #endif | ||
109 | size_t new_n = n; | ||
110 | new_n += header_size; | ||
111 | |||
112 | /* Check for overflow attack */ | ||
113 | if (new_n < n) return NULL; | ||
114 | |||
115 | #ifdef OTRL_MEM_MAGIC | ||
116 | if (magic != OTRL_MEM_MAGIC) { | ||
117 | fprintf(stderr, "Illegal realloc!\n"); | ||
118 | return NULL; | ||
119 | } | ||
120 | #endif | ||
121 | |||
122 | if (new_n < old_n) { | ||
123 | /* Overwrite the space we're about to stop using */ | ||
124 | void *p = (void *)((char *)real_p + new_n); | ||
125 | size_t excess = old_n - new_n; | ||
126 | memset(p, 0xff, excess); | ||
127 | memset(p, 0xaa, excess); | ||
128 | memset(p, 0x55, excess); | ||
129 | memset(p, 0x00, excess); | ||
130 | |||
131 | /* We don't actually need to realloc() */ | ||
132 | new_p = real_p; | ||
133 | } else { | ||
134 | new_p = realloc(real_p, new_n); | ||
135 | if (new_p == NULL) return NULL; | ||
136 | } | ||
137 | |||
138 | ((size_t *)new_p)[0] = new_n; /* Includes header size */ | ||
139 | return (void *)((char *)new_p + header_size); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | void otrl_mem_init(void) | ||
144 | { | ||
145 | header_size = 8; | ||
146 | #ifdef OTRL_MEM_MAGIC | ||
147 | if (header_size < 2*sizeof(size_t)) { | ||
148 | header_size = 2*sizeof(size_t); | ||
149 | } | ||
150 | #else | ||
151 | if (header_size < sizeof(size_t)) { | ||
152 | header_size = sizeof(size_t); | ||
153 | } | ||
154 | #endif | ||
155 | |||
156 | gcry_set_allocation_handler( | ||
157 | otrl_mem_malloc, | ||
158 | otrl_mem_malloc, | ||
159 | otrl_mem_is_secure, | ||
160 | otrl_mem_realloc, | ||
161 | otrl_mem_free | ||
162 | ); | ||
163 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/mem.h b/linden/indra/libotr/libotr-3.2.0/src/mem.h new file mode 100755 index 0000000..19e00cf --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/mem.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __MEM_H__ | ||
21 | #define __MEM_H__ | ||
22 | |||
23 | void otrl_mem_init(void); | ||
24 | |||
25 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/message.c b/linden/indra/libotr/libotr-3.2.0/src/message.c new file mode 100755 index 0000000..75791b3 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/message.c | |||
@@ -0,0 +1,1455 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* system headers */ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <time.h> | ||
24 | |||
25 | /* libgcrypt headers */ | ||
26 | #include <gcrypt.h> | ||
27 | |||
28 | /* libotr headers */ | ||
29 | #include "privkey.h" | ||
30 | #include "proto.h" | ||
31 | #include "auth.h" | ||
32 | #include "message.h" | ||
33 | #include "sm.h" | ||
34 | |||
35 | /* The API version */ | ||
36 | extern unsigned int otrl_api_version; | ||
37 | |||
38 | /* How long after sending a packet should we wait to send a heartbeat? */ | ||
39 | #define HEARTBEAT_INTERVAL 60 | ||
40 | |||
41 | /* How old are messages allowed to be in order to be candidates for | ||
42 | * resending in response to a rekey? */ | ||
43 | #define RESEND_INTERVAL 60 | ||
44 | |||
45 | /* Deallocate a message allocated by other otrl_message_* routines. */ | ||
46 | void otrl_message_free(char *message) | ||
47 | { | ||
48 | free(message); | ||
49 | } | ||
50 | |||
51 | /* Handle a message about to be sent to the network. It is safe to pass | ||
52 | * all messages about to be sent to this routine. add_appdata is a | ||
53 | * function that will be called in the event that a new ConnContext is | ||
54 | * created. It will be passed the data that you supplied, as well as a | ||
55 | * pointer to the new ConnContext. You can use this to add | ||
56 | * application-specific information to the ConnContext using the | ||
57 | * "context->app" field, for example. If you don't need to do this, you | ||
58 | * can pass NULL for the last two arguments of otrl_message_sending. | ||
59 | * | ||
60 | * tlvs is a chain of OtrlTLVs to append to the private message. It is | ||
61 | * usually correct to just pass NULL here. | ||
62 | * | ||
63 | * If this routine returns non-zero, then the library tried to encrypt | ||
64 | * the message, but for some reason failed. DO NOT send the message in | ||
65 | * the clear in that case. | ||
66 | * | ||
67 | * If *messagep gets set by the call to something non-NULL, then you | ||
68 | * should replace your message with the contents of *messagep, and | ||
69 | * send that instead. Call otrl_message_free(*messagep) when you're | ||
70 | * done with it. */ | ||
71 | gcry_error_t otrl_message_sending(OtrlUserState us, | ||
72 | const OtrlMessageAppOps *ops, | ||
73 | void *opdata, const char *accountname, const char *protocol, | ||
74 | const char *recipient, const char *message, OtrlTLV *tlvs, | ||
75 | char **messagep, | ||
76 | void (*add_appdata)(void *data, ConnContext *context), | ||
77 | void *data) | ||
78 | { | ||
79 | struct context * context; | ||
80 | char * msgtosend; | ||
81 | gcry_error_t err; | ||
82 | OtrlPolicy policy = OTRL_POLICY_DEFAULT; | ||
83 | int context_added = 0; | ||
84 | |||
85 | *messagep = NULL; | ||
86 | |||
87 | if (!accountname || !protocol || !recipient || !message || !messagep) | ||
88 | return gcry_error(GPG_ERR_NO_ERROR); | ||
89 | |||
90 | /* See if we have a fingerprint for this user */ | ||
91 | context = otrl_context_find(us, recipient, accountname, protocol, | ||
92 | 1, &context_added, add_appdata, data); | ||
93 | |||
94 | /* Update the context list if we added one */ | ||
95 | if (context_added && ops->update_context_list) { | ||
96 | ops->update_context_list(opdata); | ||
97 | } | ||
98 | |||
99 | /* Check the policy */ | ||
100 | if (ops->policy) { | ||
101 | policy = ops->policy(opdata, context); | ||
102 | } | ||
103 | |||
104 | /* Should we go on at all? */ | ||
105 | if ((policy & OTRL_POLICY_VERSION_MASK) == 0) { | ||
106 | return gcry_error(GPG_ERR_NO_ERROR); | ||
107 | } | ||
108 | |||
109 | /* If this is an OTR Query message, don't encrypt it. */ | ||
110 | if (otrl_proto_message_type(message) == OTRL_MSGTYPE_QUERY) { | ||
111 | /* Replace the "?OTR?" with a custom message */ | ||
112 | char *bettermsg = otrl_proto_default_query_msg(accountname, policy); | ||
113 | if (bettermsg) { | ||
114 | *messagep = bettermsg; | ||
115 | } | ||
116 | return gcry_error(GPG_ERR_NO_ERROR); | ||
117 | } | ||
118 | |||
119 | /* What is the current message disposition? */ | ||
120 | switch(context->msgstate) { | ||
121 | case OTRL_MSGSTATE_PLAINTEXT: | ||
122 | if ((policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) { | ||
123 | /* We're trying to send an unencrypted message with a policy | ||
124 | * that disallows that. Don't do that, but try to start | ||
125 | * up OTR instead. */ | ||
126 | if ((!(ops->display_otr_message) || | ||
127 | ops->display_otr_message(opdata, accountname, | ||
128 | protocol, recipient, "Attempting to start a " | ||
129 | "private conversation...")) && ops->notify) { | ||
130 | const char *format = "You attempted to send an " | ||
131 | "unencrypted message to %s"; | ||
132 | char *primary = malloc(strlen(format) + | ||
133 | strlen(recipient) - 1); | ||
134 | if (primary) { | ||
135 | sprintf(primary, format, recipient); | ||
136 | ops->notify(opdata, OTRL_NOTIFY_WARNING, accountname, | ||
137 | protocol, recipient, "OTR Policy Violation", | ||
138 | primary, | ||
139 | "Unencrypted messages to this recipient are " | ||
140 | "not allowed. Attempting to start a private " | ||
141 | "conversation.\n\nYour message will be " | ||
142 | "retransmitted when the private conversation " | ||
143 | "starts."); | ||
144 | free(primary); | ||
145 | } | ||
146 | } | ||
147 | context->lastmessage = gcry_malloc_secure(strlen(message) + 1); | ||
148 | if (context->lastmessage) { | ||
149 | char *bettermsg = otrl_proto_default_query_msg(accountname, | ||
150 | policy); | ||
151 | strcpy(context->lastmessage, message); | ||
152 | context->lastsent = time(NULL); | ||
153 | context->may_retransmit = 2; | ||
154 | if (bettermsg) { | ||
155 | *messagep = bettermsg; | ||
156 | } else { | ||
157 | return gcry_error(GPG_ERR_ENOMEM); | ||
158 | } | ||
159 | } | ||
160 | } else { | ||
161 | if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG) && | ||
162 | context->otr_offer != OFFER_REJECTED) { | ||
163 | /* See if this user can speak OTR. Append the | ||
164 | * OTR_MESSAGE_TAG to the plaintext message, and see | ||
165 | * if he responds. */ | ||
166 | size_t msglen = strlen(message); | ||
167 | size_t basetaglen = strlen(OTRL_MESSAGE_TAG_BASE); | ||
168 | size_t v1taglen = (policy & OTRL_POLICY_ALLOW_V1) ? | ||
169 | strlen(OTRL_MESSAGE_TAG_V1) : 0; | ||
170 | size_t v2taglen = (policy & OTRL_POLICY_ALLOW_V2) ? | ||
171 | strlen(OTRL_MESSAGE_TAG_V2) : 0; | ||
172 | char *taggedmsg = malloc(msglen + basetaglen + v1taglen | ||
173 | +v2taglen + 1); | ||
174 | if (taggedmsg) { | ||
175 | strcpy(taggedmsg, message); | ||
176 | strcpy(taggedmsg + msglen, OTRL_MESSAGE_TAG_BASE); | ||
177 | if (v1taglen) { | ||
178 | strcpy(taggedmsg + msglen + basetaglen, | ||
179 | OTRL_MESSAGE_TAG_V1); | ||
180 | } | ||
181 | if (v2taglen) { | ||
182 | strcpy(taggedmsg + msglen + basetaglen + v1taglen, | ||
183 | OTRL_MESSAGE_TAG_V2); | ||
184 | } | ||
185 | *messagep = taggedmsg; | ||
186 | if (context) { | ||
187 | context->otr_offer = OFFER_SENT; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | break; | ||
193 | case OTRL_MSGSTATE_ENCRYPTED: | ||
194 | /* Create the new, encrypted message */ | ||
195 | err = otrl_proto_create_data(&msgtosend, context, message, tlvs, | ||
196 | 0); | ||
197 | if (!err) { | ||
198 | context->lastsent = time(NULL); | ||
199 | *messagep = msgtosend; | ||
200 | } else { | ||
201 | /* Uh, oh. Whatever we do, *don't* send the message in the | ||
202 | * clear. */ | ||
203 | *messagep = strdup("?OTR Error: Error occurred encrypting " | ||
204 | "message"); | ||
205 | if ((!(ops->display_otr_message) || | ||
206 | ops->display_otr_message(opdata, accountname, | ||
207 | protocol, recipient, "An error occurred when " | ||
208 | "encrypting your message. The message was not " | ||
209 | "sent.")) && ops->notify) { | ||
210 | ops->notify(opdata, OTRL_NOTIFY_ERROR, | ||
211 | accountname, protocol, recipient, | ||
212 | "Error encrypting message", | ||
213 | "An error occurred when encrypting your message", | ||
214 | "The message was not sent."); | ||
215 | } | ||
216 | if (!(*messagep)) { | ||
217 | return gcry_error(GPG_ERR_ENOMEM); | ||
218 | } | ||
219 | } | ||
220 | break; | ||
221 | case OTRL_MSGSTATE_FINISHED: | ||
222 | *messagep = strdup(""); | ||
223 | if ((!(ops->display_otr_message) || | ||
224 | ops->display_otr_message(opdata, accountname, | ||
225 | protocol, recipient, "Your message was not sent. " | ||
226 | "Either end your private conversation, or restart " | ||
227 | "it.")) && ops->notify) { | ||
228 | const char *fmt = "%s has already closed his/her private " | ||
229 | "connection to you"; | ||
230 | char *primary = malloc(strlen(fmt) + strlen(recipient) - 1); | ||
231 | if (primary) { | ||
232 | sprintf(primary, fmt, recipient); | ||
233 | ops->notify(opdata, OTRL_NOTIFY_ERROR, | ||
234 | accountname, protocol, recipient, | ||
235 | "Private connection closed", primary, | ||
236 | "Your message was not sent. Either close your " | ||
237 | "private connection to him, or refresh it."); | ||
238 | } | ||
239 | } | ||
240 | if (!(*messagep)) { | ||
241 | return gcry_error(GPG_ERR_ENOMEM); | ||
242 | } | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | return gcry_error(GPG_ERR_NO_ERROR); | ||
247 | } | ||
248 | |||
249 | /* If err == 0, send the last auth message for the given context to the | ||
250 | * appropriate user. Otherwise, display an appripriate error dialog. | ||
251 | * Return the value of err that was passed. */ | ||
252 | static gcry_error_t send_or_error_auth(const OtrlMessageAppOps *ops, | ||
253 | void *opdata, gcry_error_t err, ConnContext *context) | ||
254 | { | ||
255 | if (!err) { | ||
256 | const char *msg = context->auth.lastauthmsg; | ||
257 | if (msg && *msg) { | ||
258 | otrl_message_fragment_and_send(ops, opdata, context, msg, OTRL_FRAGMENT_SEND_ALL, NULL); | ||
259 | /*if (ops->inject_message) { | ||
260 | ops->inject_message(opdata, context->accountname, | ||
261 | context->protocol, context->username, msg); | ||
262 | }*/ | ||
263 | } | ||
264 | } else { | ||
265 | const char *buf_format = "Error setting up private conversation: %s"; | ||
266 | const char *strerr; | ||
267 | char *buf; | ||
268 | |||
269 | switch(gcry_err_code(err)) { | ||
270 | case GPG_ERR_INV_VALUE: | ||
271 | strerr = "Malformed message received"; | ||
272 | break; | ||
273 | default: | ||
274 | strerr = gcry_strerror(err); | ||
275 | break; | ||
276 | } | ||
277 | buf = malloc(strlen(buf_format) + strlen(strerr) - 1); | ||
278 | if (buf) { | ||
279 | sprintf(buf, buf_format, strerr); | ||
280 | } | ||
281 | if ((!(ops->display_otr_message) || | ||
282 | ops->display_otr_message(opdata, context->accountname, | ||
283 | context->protocol, context->username, buf)) | ||
284 | && ops->notify) { | ||
285 | ops->notify(opdata, OTRL_NOTIFY_ERROR, context->accountname, | ||
286 | context->protocol, context->username, "OTR error", | ||
287 | buf, NULL); | ||
288 | } | ||
289 | free(buf); | ||
290 | } | ||
291 | return err; | ||
292 | } | ||
293 | |||
294 | typedef struct { | ||
295 | int gone_encrypted; | ||
296 | OtrlUserState us; | ||
297 | const OtrlMessageAppOps *ops; | ||
298 | void *opdata; | ||
299 | ConnContext *context; | ||
300 | int ignore_message; | ||
301 | char **messagep; | ||
302 | } EncrData; | ||
303 | |||
304 | static gcry_error_t go_encrypted(const OtrlAuthInfo *auth, void *asdata) | ||
305 | { | ||
306 | EncrData *edata = asdata; | ||
307 | gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR); | ||
308 | Fingerprint *found_print = NULL; | ||
309 | int fprint_added = 0; | ||
310 | OtrlMessageState oldstate = edata->context->msgstate; | ||
311 | Fingerprint *oldprint = edata->context->active_fingerprint; | ||
312 | |||
313 | /* See if we're talking to ourselves */ | ||
314 | if (!gcry_mpi_cmp(auth->their_pub, auth->our_dh.pub)) { | ||
315 | /* Yes, we are. */ | ||
316 | if ((!(edata->ops->display_otr_message) || | ||
317 | edata->ops->display_otr_message(edata->opdata, | ||
318 | edata->context->accountname, edata->context->protocol, | ||
319 | edata->context->username, | ||
320 | "We are receiving our own OTR messages. " | ||
321 | "You are either trying to talk to yourself, " | ||
322 | "or someone is reflecting your messages back " | ||
323 | "at you.")) && edata->ops->notify) { | ||
324 | edata->ops->notify(edata->opdata, OTRL_NOTIFY_ERROR, | ||
325 | edata->context->accountname, edata->context->protocol, | ||
326 | edata->context->username, "OTR Error", | ||
327 | "We are receiving our own OTR messages.", | ||
328 | "You are either trying to talk to yourself, " | ||
329 | "or someone is reflecting your messages back " | ||
330 | "at you."); | ||
331 | } | ||
332 | edata->ignore_message = 1; | ||
333 | return gcry_error(GPG_ERR_NO_ERROR); | ||
334 | } | ||
335 | |||
336 | found_print = otrl_context_find_fingerprint(edata->context, | ||
337 | edata->context->auth.their_fingerprint, 1, &fprint_added); | ||
338 | |||
339 | if (fprint_added) { | ||
340 | /* Inform the user of the new fingerprint */ | ||
341 | if (edata->ops->new_fingerprint) { | ||
342 | edata->ops->new_fingerprint(edata->opdata, edata->us, | ||
343 | edata->context->accountname, edata->context->protocol, | ||
344 | edata->context->username, | ||
345 | edata->context->auth.their_fingerprint); | ||
346 | } | ||
347 | /* Arrange that the new fingerprint be written to disk */ | ||
348 | if (edata->ops->write_fingerprints) { | ||
349 | edata->ops->write_fingerprints(edata->opdata); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | /* Is this a new session or just a refresh of an existing one? */ | ||
354 | if (edata->context->msgstate == OTRL_MSGSTATE_ENCRYPTED && | ||
355 | oldprint == found_print && | ||
356 | edata->context->our_keyid - 1 == edata->context->auth.our_keyid && | ||
357 | !gcry_mpi_cmp(edata->context->our_old_dh_key.pub, | ||
358 | edata->context->auth.our_dh.pub) && | ||
359 | ((edata->context->their_keyid > 0 && | ||
360 | edata->context->their_keyid == | ||
361 | edata->context->auth.their_keyid && | ||
362 | !gcry_mpi_cmp(edata->context->their_y, | ||
363 | edata->context->auth.their_pub)) || | ||
364 | (edata->context->their_keyid > 1 && | ||
365 | edata->context->their_keyid - 1 == | ||
366 | edata->context->auth.their_keyid && | ||
367 | edata->context->their_old_y != NULL && | ||
368 | !gcry_mpi_cmp(edata->context->their_old_y, | ||
369 | edata->context->auth.their_pub)))) { | ||
370 | /* This is just a refresh of the existing session. */ | ||
371 | if (edata->ops->still_secure) { | ||
372 | edata->ops->still_secure(edata->opdata, edata->context, | ||
373 | edata->context->auth.initiated); | ||
374 | } | ||
375 | edata->ignore_message = 1; | ||
376 | return gcry_error(GPG_ERR_NO_ERROR); | ||
377 | } | ||
378 | |||
379 | /* Copy the information from the auth into the context */ | ||
380 | memmove(edata->context->sessionid, | ||
381 | edata->context->auth.secure_session_id, 20); | ||
382 | edata->context->sessionid_len = | ||
383 | edata->context->auth.secure_session_id_len; | ||
384 | edata->context->sessionid_half = | ||
385 | edata->context->auth.session_id_half; | ||
386 | edata->context->protocol_version = | ||
387 | edata->context->auth.protocol_version; | ||
388 | |||
389 | edata->context->their_keyid = edata->context->auth.their_keyid; | ||
390 | gcry_mpi_release(edata->context->their_y); | ||
391 | gcry_mpi_release(edata->context->their_old_y); | ||
392 | edata->context->their_y = gcry_mpi_copy(edata->context->auth.their_pub); | ||
393 | edata->context->their_old_y = NULL; | ||
394 | |||
395 | if (edata->context->our_keyid - 1 != edata->context->auth.our_keyid || | ||
396 | gcry_mpi_cmp(edata->context->our_old_dh_key.pub, | ||
397 | edata->context->auth.our_dh.pub)) { | ||
398 | otrl_dh_keypair_free(&(edata->context->our_dh_key)); | ||
399 | otrl_dh_keypair_free(&(edata->context->our_old_dh_key)); | ||
400 | otrl_dh_keypair_copy(&(edata->context->our_old_dh_key), | ||
401 | &(edata->context->auth.our_dh)); | ||
402 | otrl_dh_gen_keypair(edata->context->our_old_dh_key.groupid, | ||
403 | &(edata->context->our_dh_key)); | ||
404 | edata->context->our_keyid = edata->context->auth.our_keyid + 1; | ||
405 | } | ||
406 | |||
407 | /* Create the session keys from the DH keys */ | ||
408 | otrl_dh_session_free(&(edata->context->sesskeys[0][0])); | ||
409 | err = otrl_dh_session(&(edata->context->sesskeys[0][0]), | ||
410 | &(edata->context->our_dh_key), edata->context->their_y); | ||
411 | if (err) return err; | ||
412 | otrl_dh_session_free(&(edata->context->sesskeys[1][0])); | ||
413 | err = otrl_dh_session(&(edata->context->sesskeys[1][0]), | ||
414 | &(edata->context->our_old_dh_key), edata->context->their_y); | ||
415 | if (err) return err; | ||
416 | |||
417 | edata->context->generation++; | ||
418 | edata->context->active_fingerprint = found_print; | ||
419 | edata->context->msgstate = OTRL_MSGSTATE_ENCRYPTED; | ||
420 | |||
421 | if (edata->ops->update_context_list) { | ||
422 | edata->ops->update_context_list(edata->opdata); | ||
423 | } | ||
424 | if (oldstate == OTRL_MSGSTATE_ENCRYPTED && oldprint == found_print) { | ||
425 | if (edata->ops->still_secure) { | ||
426 | edata->ops->still_secure(edata->opdata, edata->context, | ||
427 | edata->context->auth.initiated); | ||
428 | } | ||
429 | } else { | ||
430 | if (edata->ops->gone_secure) { | ||
431 | edata->ops->gone_secure(edata->opdata, edata->context); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | edata->gone_encrypted = 1; | ||
436 | |||
437 | return gpg_error(GPG_ERR_NO_ERROR); | ||
438 | } | ||
439 | |||
440 | static void maybe_resend(EncrData *edata) | ||
441 | { | ||
442 | gcry_error_t err; | ||
443 | time_t now; | ||
444 | |||
445 | if (!edata->gone_encrypted) return; | ||
446 | |||
447 | /* See if there's a message we sent recently that should be resent. */ | ||
448 | now = time(NULL); | ||
449 | if (edata->context->lastmessage != NULL && | ||
450 | edata->context->may_retransmit && | ||
451 | edata->context->lastsent >= (now - RESEND_INTERVAL)) { | ||
452 | char *resendmsg; | ||
453 | int resending = (edata->context->may_retransmit == 1); | ||
454 | |||
455 | /* Re-encrypt the message with the new keys */ | ||
456 | err = otrl_proto_create_data(&resendmsg, | ||
457 | edata->context, edata->context->lastmessage, NULL, 0); | ||
458 | if (!err) { | ||
459 | //const char *format = "The last message " | ||
460 | //"to %s was resent."; | ||
461 | //char *buf; | ||
462 | |||
463 | /* Resend the message */ | ||
464 | otrl_message_fragment_and_send(edata->ops, edata->opdata, edata->context, resendmsg, OTRL_FRAGMENT_SEND_ALL, NULL); | ||
465 | free(resendmsg); | ||
466 | edata->context->lastsent = now; | ||
467 | |||
468 | if (!resending) { | ||
469 | /* We're actually just sending it | ||
470 | * for the first time. */ | ||
471 | edata->ignore_message = 1; | ||
472 | } /*else { | ||
473 | // Let the user know we resent it | ||
474 | buf = malloc(strlen(format) + | ||
475 | strlen(edata->context->username) - 1); | ||
476 | if (buf) { | ||
477 | sprintf(buf, format, edata->context->username); | ||
478 | if (edata->ops->display_otr_message) { | ||
479 | if (!edata->ops->display_otr_message( | ||
480 | edata->opdata, edata->context->accountname, | ||
481 | edata->context->protocol, | ||
482 | edata->context->username, buf)) { | ||
483 | edata->ignore_message = 1; | ||
484 | } | ||
485 | } | ||
486 | if (edata->ignore_message != 1) { | ||
487 | *(edata->messagep) = buf; | ||
488 | edata->ignore_message = 0; | ||
489 | } else { | ||
490 | free(buf); | ||
491 | } | ||
492 | } | ||
493 | }*/ | ||
494 | } | ||
495 | } | ||
496 | } | ||
497 | |||
498 | /* Set the trust level based on the result of the SMP */ | ||
499 | static void set_smp_trust(const OtrlMessageAppOps *ops, void *opdata, | ||
500 | ConnContext *context, int trusted) | ||
501 | { | ||
502 | otrl_context_set_trust(context->active_fingerprint, trusted ? "smp" : ""); | ||
503 | |||
504 | /* Write the new info to disk, redraw the ui, and redraw the | ||
505 | * OTR buttons. */ | ||
506 | if (ops->write_fingerprints) { | ||
507 | ops->write_fingerprints(opdata); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | static void init_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
512 | void *opdata, ConnContext *context, const char *question, | ||
513 | const unsigned char *secret, size_t secretlen, int initiating) | ||
514 | { | ||
515 | unsigned char *smpmsg = NULL; | ||
516 | int smpmsglen; | ||
517 | unsigned char combined_secret[SM_DIGEST_SIZE]; | ||
518 | gcry_error_t err; | ||
519 | unsigned char our_fp[20]; | ||
520 | unsigned char *combined_buf; | ||
521 | size_t combined_buf_len; | ||
522 | OtrlTLV *sendtlv; | ||
523 | char *sendsmp = NULL; | ||
524 | |||
525 | if (!context || context->msgstate != OTRL_MSGSTATE_ENCRYPTED) return; | ||
526 | |||
527 | /* | ||
528 | * Construct the combined secret as a SHA256 hash of: | ||
529 | * Version byte (0x01), Initiator fingerprint (20 bytes), | ||
530 | * responder fingerprint (20 bytes), secure session id, input secret | ||
531 | */ | ||
532 | otrl_privkey_fingerprint_raw(us, our_fp, context->accountname, | ||
533 | context->protocol); | ||
534 | |||
535 | combined_buf_len = 41 + context->sessionid_len + secretlen; | ||
536 | combined_buf = malloc(combined_buf_len); | ||
537 | combined_buf[0] = 0x01; | ||
538 | if (initiating) { | ||
539 | memmove(combined_buf + 1, our_fp, 20); | ||
540 | memmove(combined_buf + 21, | ||
541 | context->active_fingerprint->fingerprint, 20); | ||
542 | } else { | ||
543 | memmove(combined_buf + 1, | ||
544 | context->active_fingerprint->fingerprint, 20); | ||
545 | memmove(combined_buf + 21, our_fp, 20); | ||
546 | } | ||
547 | memmove(combined_buf + 41, context->sessionid, | ||
548 | context->sessionid_len); | ||
549 | memmove(combined_buf + 41 + context->sessionid_len, | ||
550 | secret, secretlen); | ||
551 | gcry_md_hash_buffer(SM_HASH_ALGORITHM, combined_secret, combined_buf, | ||
552 | combined_buf_len); | ||
553 | free(combined_buf); | ||
554 | |||
555 | if (initiating) { | ||
556 | otrl_sm_step1(context->smstate, combined_secret, SM_DIGEST_SIZE, | ||
557 | &smpmsg, &smpmsglen); | ||
558 | } else { | ||
559 | otrl_sm_step2b(context->smstate, combined_secret, SM_DIGEST_SIZE, | ||
560 | &smpmsg, &smpmsglen); | ||
561 | } | ||
562 | |||
563 | /* If we've got a question, attach it to the smpmsg */ | ||
564 | if (question != NULL) { | ||
565 | size_t qlen = strlen(question); | ||
566 | unsigned char *qsmpmsg = malloc(qlen + 1 + smpmsglen); | ||
567 | if (!qsmpmsg) { | ||
568 | free(smpmsg); | ||
569 | return; | ||
570 | } | ||
571 | strcpy((char *)qsmpmsg, question); | ||
572 | memmove(qsmpmsg + qlen + 1, smpmsg, smpmsglen); | ||
573 | free(smpmsg); | ||
574 | smpmsg = qsmpmsg; | ||
575 | smpmsglen += qlen + 1; | ||
576 | } | ||
577 | |||
578 | /* Send msg with next smp msg content */ | ||
579 | sendtlv = otrl_tlv_new(initiating ? | ||
580 | (question != NULL ? OTRL_TLV_SMP1Q : OTRL_TLV_SMP1) | ||
581 | : OTRL_TLV_SMP2, | ||
582 | smpmsglen, smpmsg); | ||
583 | err = otrl_proto_create_data(&sendsmp, context, "", sendtlv, | ||
584 | OTRL_MSGFLAGS_IGNORE_UNREADABLE); | ||
585 | if (!err) { | ||
586 | /* Send it, and set the next expected message to the | ||
587 | * logical response */ | ||
588 | err = otrl_message_fragment_and_send(ops, opdata, context, | ||
589 | sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL); | ||
590 | context->smstate->nextExpected = | ||
591 | initiating ? OTRL_SMP_EXPECT2 : OTRL_SMP_EXPECT3; | ||
592 | } | ||
593 | free(sendsmp); | ||
594 | otrl_tlv_free(sendtlv); | ||
595 | free(smpmsg); | ||
596 | } | ||
597 | |||
598 | /* Initiate the Socialist Millionaires' Protocol */ | ||
599 | void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
600 | void *opdata, ConnContext *context, const unsigned char *secret, | ||
601 | size_t secretlen) | ||
602 | { | ||
603 | init_respond_smp(us, ops, opdata, context, NULL, secret, secretlen, 1); | ||
604 | } | ||
605 | |||
606 | /* Initiate the Socialist Millionaires' Protocol and send a prompt | ||
607 | * question to the buddy */ | ||
608 | void otrl_message_initiate_smp_q(OtrlUserState us, | ||
609 | const OtrlMessageAppOps *ops, void *opdata, ConnContext *context, | ||
610 | const char *question, const unsigned char *secret, size_t secretlen) | ||
611 | { | ||
612 | init_respond_smp(us, ops, opdata, context, question, secret, secretlen, 1); | ||
613 | } | ||
614 | |||
615 | /* Respond to a buddy initiating the Socialist Millionaires' Protocol */ | ||
616 | void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
617 | void *opdata, ConnContext *context, const unsigned char *secret, | ||
618 | size_t secretlen) | ||
619 | { | ||
620 | init_respond_smp(us, ops, opdata, context, NULL, secret, secretlen, 0); | ||
621 | } | ||
622 | |||
623 | /* Abort the SMP. Called when an unexpected SMP message breaks the | ||
624 | * normal flow. */ | ||
625 | void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
626 | void *opdata, ConnContext *context) | ||
627 | { | ||
628 | OtrlTLV *sendtlv = otrl_tlv_new(OTRL_TLV_SMP_ABORT, 0, | ||
629 | (const unsigned char *)""); | ||
630 | char *sendsmp = NULL; | ||
631 | gcry_error_t err; | ||
632 | |||
633 | context->smstate->nextExpected = OTRL_SMP_EXPECT1; | ||
634 | |||
635 | err = otrl_proto_create_data(&sendsmp, | ||
636 | context, "", sendtlv, | ||
637 | OTRL_MSGFLAGS_IGNORE_UNREADABLE); | ||
638 | if (!err) { | ||
639 | /* Send the abort signal so our buddy knows we've stopped */ | ||
640 | err = otrl_message_fragment_and_send(ops, opdata, context, | ||
641 | sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL); | ||
642 | } | ||
643 | free(sendsmp); | ||
644 | otrl_tlv_free(sendtlv); | ||
645 | } | ||
646 | |||
647 | /* Handle a message just received from the network. It is safe to pass | ||
648 | * all received messages to this routine. add_appdata is a function | ||
649 | * that will be called in the event that a new ConnContext is created. | ||
650 | * It will be passed the data that you supplied, as well as | ||
651 | * a pointer to the new ConnContext. You can use this to add | ||
652 | * application-specific information to the ConnContext using the | ||
653 | * "context->app" field, for example. If you don't need to do this, you | ||
654 | * can pass NULL for the last two arguments of otrl_message_receiving. | ||
655 | * | ||
656 | * If otrl_message_receiving returns 1, then the message you received | ||
657 | * was an internal protocol message, and no message should be delivered | ||
658 | * to the user. | ||
659 | * | ||
660 | * If it returns 0, then check if *messagep was set to non-NULL. If | ||
661 | * so, replace the received message with the contents of *messagep, and | ||
662 | * deliver that to the user instead. You must call | ||
663 | * otrl_message_free(*messagep) when you're done with it. If tlvsp is | ||
664 | * non-NULL, *tlvsp will be set to a chain of any TLVs that were | ||
665 | * transmitted along with this message. You must call | ||
666 | * otrl_tlv_free(*tlvsp) when you're done with those. | ||
667 | * | ||
668 | * If otrl_message_receiving returns 0 and *messagep is NULL, then this | ||
669 | * was an ordinary, non-OTR message, which should just be delivered to | ||
670 | * the user without modification. */ | ||
671 | int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
672 | void *opdata, const char *accountname, const char *protocol, | ||
673 | const char *sender, const char *message, char **newmessagep, | ||
674 | OtrlTLV **tlvsp, | ||
675 | void (*add_appdata)(void *data, ConnContext *context), | ||
676 | void *data) | ||
677 | { | ||
678 | ConnContext *context; | ||
679 | OtrlMessageType msgtype; | ||
680 | int context_added = 0; | ||
681 | OtrlMessageState msgstate; | ||
682 | OtrlPolicy policy = OTRL_POLICY_DEFAULT; | ||
683 | int fragment_assembled = 0; | ||
684 | char *unfragmessage = NULL; | ||
685 | EncrData edata; | ||
686 | |||
687 | if (!accountname || !protocol || !sender || !message || !newmessagep) | ||
688 | return 0; | ||
689 | |||
690 | *newmessagep = NULL; | ||
691 | if (tlvsp) *tlvsp = NULL; | ||
692 | |||
693 | /* Find our context and state with this correspondent */ | ||
694 | context = otrl_context_find(us, sender, accountname, | ||
695 | protocol, 1, &context_added, add_appdata, data); | ||
696 | |||
697 | /* Update the context list if we added one */ | ||
698 | if (context_added && ops->update_context_list) { | ||
699 | ops->update_context_list(opdata); | ||
700 | } | ||
701 | |||
702 | /* Check the policy */ | ||
703 | if (ops->policy) { | ||
704 | policy = ops->policy(opdata, context); | ||
705 | } | ||
706 | |||
707 | /* Should we go on at all? */ | ||
708 | if ((policy & OTRL_POLICY_VERSION_MASK) == 0) { | ||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | /* See if we have a fragment */ | ||
713 | switch(otrl_proto_fragment_accumulate(&unfragmessage, context, message)) { | ||
714 | case OTRL_FRAGMENT_UNFRAGMENTED: | ||
715 | /* Do nothing */ | ||
716 | break; | ||
717 | case OTRL_FRAGMENT_INCOMPLETE: | ||
718 | /* We've accumulated this fragment, but we don't have a | ||
719 | * complete message yet */ | ||
720 | return 1; | ||
721 | case OTRL_FRAGMENT_COMPLETE: | ||
722 | /* We've got a new complete message, in unfragmessage. */ | ||
723 | fragment_assembled = 1; | ||
724 | message = unfragmessage; | ||
725 | break; | ||
726 | } | ||
727 | |||
728 | /* What type of message is it? Note that this just checks the | ||
729 | * header; it's not necessarily a _valid_ message of this type. */ | ||
730 | msgtype = otrl_proto_message_type(message); | ||
731 | msgstate = context->msgstate; | ||
732 | |||
733 | /* See if they responded to our OTR offer */ | ||
734 | if ((policy & OTRL_POLICY_SEND_WHITESPACE_TAG)) { | ||
735 | if (msgtype != OTRL_MSGTYPE_NOTOTR) { | ||
736 | context->otr_offer = OFFER_ACCEPTED; | ||
737 | } else if (context->otr_offer == OFFER_SENT) { | ||
738 | context->otr_offer = OFFER_REJECTED; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | edata.gone_encrypted = 0; | ||
743 | edata.us = us; | ||
744 | edata.context = context; | ||
745 | edata.ops = ops; | ||
746 | edata.opdata = opdata; | ||
747 | edata.ignore_message = -1; | ||
748 | edata.messagep = newmessagep; | ||
749 | |||
750 | switch(msgtype) { | ||
751 | unsigned int bestversion; | ||
752 | const char *startwhite, *endwhite; | ||
753 | DH_keypair *our_dh; | ||
754 | unsigned int our_keyid; | ||
755 | OtrlPrivKey *privkey; | ||
756 | gcry_error_t err; | ||
757 | int haveauthmsg; | ||
758 | case OTRL_MSGTYPE_QUERY: | ||
759 | /* See if we should use an existing DH keypair, or generate | ||
760 | * a fresh one. */ | ||
761 | if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { | ||
762 | our_dh = &(context->our_old_dh_key); | ||
763 | our_keyid = context->our_keyid - 1; | ||
764 | } else { | ||
765 | our_dh = NULL; | ||
766 | our_keyid = 0; | ||
767 | } | ||
768 | |||
769 | /* Find the best version of OTR that we both speak */ | ||
770 | switch(otrl_proto_query_bestversion(message, policy)) { | ||
771 | case 2: | ||
772 | err = otrl_auth_start_v2(&(context->auth)); | ||
773 | send_or_error_auth(ops, opdata, err, context); | ||
774 | break; | ||
775 | case 1: | ||
776 | /* Get our private key */ | ||
777 | privkey = otrl_privkey_find(us, context->accountname, | ||
778 | context->protocol); | ||
779 | if (privkey == NULL) { | ||
780 | /* We've got no private key! */ | ||
781 | if (ops->create_privkey) { | ||
782 | ops->create_privkey(opdata, context->accountname, | ||
783 | context->protocol); | ||
784 | privkey = otrl_privkey_find(us, | ||
785 | context->accountname, context->protocol); | ||
786 | } | ||
787 | } | ||
788 | if (privkey) { | ||
789 | err = otrl_auth_start_v1(&(context->auth), our_dh, | ||
790 | our_keyid, privkey); | ||
791 | send_or_error_auth(ops, opdata, err, context); | ||
792 | } | ||
793 | break; | ||
794 | default: | ||
795 | /* Just ignore this message */ | ||
796 | break; | ||
797 | } | ||
798 | /* Don't display the Query message to the user. */ | ||
799 | if (edata.ignore_message == -1) edata.ignore_message = 1; | ||
800 | break; | ||
801 | |||
802 | case OTRL_MSGTYPE_DH_COMMIT: | ||
803 | if ((policy & OTRL_POLICY_ALLOW_V2)) { | ||
804 | err = otrl_auth_handle_commit(&(context->auth), message); | ||
805 | send_or_error_auth(ops, opdata, err, context); | ||
806 | } | ||
807 | |||
808 | if (edata.ignore_message == -1) edata.ignore_message = 1; | ||
809 | break; | ||
810 | |||
811 | case OTRL_MSGTYPE_DH_KEY: | ||
812 | if ((policy & OTRL_POLICY_ALLOW_V2)) { | ||
813 | /* Get our private key */ | ||
814 | privkey = otrl_privkey_find(us, context->accountname, | ||
815 | context->protocol); | ||
816 | if (privkey == NULL) { | ||
817 | /* We've got no private key! */ | ||
818 | if (ops->create_privkey) { | ||
819 | ops->create_privkey(opdata, context->accountname, | ||
820 | context->protocol); | ||
821 | privkey = otrl_privkey_find(us, | ||
822 | context->accountname, context->protocol); | ||
823 | } | ||
824 | } | ||
825 | if (privkey) { | ||
826 | err = otrl_auth_handle_key(&(context->auth), message, | ||
827 | &haveauthmsg, privkey); | ||
828 | if (err || haveauthmsg) { | ||
829 | send_or_error_auth(ops, opdata, err, context); | ||
830 | } | ||
831 | } | ||
832 | } | ||
833 | |||
834 | if (edata.ignore_message == -1) edata.ignore_message = 1; | ||
835 | break; | ||
836 | |||
837 | case OTRL_MSGTYPE_REVEALSIG: | ||
838 | if ((policy & OTRL_POLICY_ALLOW_V2)) { | ||
839 | /* Get our private key */ | ||
840 | privkey = otrl_privkey_find(us, context->accountname, | ||
841 | context->protocol); | ||
842 | if (privkey == NULL) { | ||
843 | /* We've got no private key! */ | ||
844 | if (ops->create_privkey) { | ||
845 | ops->create_privkey(opdata, context->accountname, | ||
846 | context->protocol); | ||
847 | privkey = otrl_privkey_find(us, | ||
848 | context->accountname, context->protocol); | ||
849 | } | ||
850 | } | ||
851 | if (privkey) { | ||
852 | err = otrl_auth_handle_revealsig(&(context->auth), | ||
853 | message, &haveauthmsg, privkey, go_encrypted, | ||
854 | &edata); | ||
855 | if (err || haveauthmsg) { | ||
856 | send_or_error_auth(ops, opdata, err, context); | ||
857 | maybe_resend(&edata); | ||
858 | } | ||
859 | } | ||
860 | } | ||
861 | |||
862 | if (edata.ignore_message == -1) edata.ignore_message = 1; | ||
863 | break; | ||
864 | |||
865 | case OTRL_MSGTYPE_SIGNATURE: | ||
866 | if ((policy & OTRL_POLICY_ALLOW_V2)) { | ||
867 | err = otrl_auth_handle_signature(&(context->auth), | ||
868 | message, &haveauthmsg, go_encrypted, &edata); | ||
869 | if (err || haveauthmsg) { | ||
870 | send_or_error_auth(ops, opdata, err, context); | ||
871 | maybe_resend(&edata); | ||
872 | } | ||
873 | } | ||
874 | |||
875 | if (edata.ignore_message == -1) edata.ignore_message = 1; | ||
876 | break; | ||
877 | |||
878 | case OTRL_MSGTYPE_V1_KEYEXCH: | ||
879 | if ((policy & OTRL_POLICY_ALLOW_V1)) { | ||
880 | /* See if we should use an existing DH keypair, or generate | ||
881 | * a fresh one. */ | ||
882 | if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { | ||
883 | our_dh = &(context->our_old_dh_key); | ||
884 | our_keyid = context->our_keyid - 1; | ||
885 | } else { | ||
886 | our_dh = NULL; | ||
887 | our_keyid = 0; | ||
888 | } | ||
889 | |||
890 | /* Get our private key */ | ||
891 | privkey = otrl_privkey_find(us, context->accountname, | ||
892 | context->protocol); | ||
893 | if (privkey == NULL) { | ||
894 | /* We've got no private key! */ | ||
895 | if (ops->create_privkey) { | ||
896 | ops->create_privkey(opdata, context->accountname, | ||
897 | context->protocol); | ||
898 | privkey = otrl_privkey_find(us, | ||
899 | context->accountname, context->protocol); | ||
900 | } | ||
901 | } | ||
902 | if (privkey) { | ||
903 | err = otrl_auth_handle_v1_key_exchange(&(context->auth), | ||
904 | message, &haveauthmsg, privkey, our_dh, our_keyid, | ||
905 | go_encrypted, &edata); | ||
906 | if (err || haveauthmsg) { | ||
907 | send_or_error_auth(ops, opdata, err, context); | ||
908 | maybe_resend(&edata); | ||
909 | } | ||
910 | } | ||
911 | } | ||
912 | |||
913 | if (edata.ignore_message == -1) edata.ignore_message = 1; | ||
914 | break; | ||
915 | |||
916 | case OTRL_MSGTYPE_DATA: | ||
917 | switch(context->msgstate) { | ||
918 | gcry_error_t err; | ||
919 | OtrlTLV *tlvs, *tlv; | ||
920 | char *plaintext; | ||
921 | char *buf; | ||
922 | const char *format; | ||
923 | const char *displayaccountname; | ||
924 | unsigned char flags; | ||
925 | NextExpectedSMP nextMsg; | ||
926 | |||
927 | case OTRL_MSGSTATE_PLAINTEXT: | ||
928 | case OTRL_MSGSTATE_FINISHED: | ||
929 | /* See if we're supposed to ignore this message in | ||
930 | * the event it's unreadable. */ | ||
931 | err = otrl_proto_data_read_flags(message, &flags); | ||
932 | if ((flags & OTRL_MSGFLAGS_IGNORE_UNREADABLE)) { | ||
933 | edata.ignore_message = 1; | ||
934 | break; | ||
935 | } | ||
936 | |||
937 | /* Don't use g_strdup_printf here, because someone | ||
938 | * (not us) is going to free() the *newmessagep pointer, | ||
939 | * not g_free() it. */ | ||
940 | format = "The encrypted message received from %s is " | ||
941 | "unreadable, as you are not currently communicating " | ||
942 | "privately."; | ||
943 | buf = malloc(strlen(format) + strlen(context->username) | ||
944 | - 1); /* Remove "%s", add username + '\0' */ | ||
945 | if (buf) { | ||
946 | sprintf(buf, format, context->username); | ||
947 | if (ops->display_otr_message) { | ||
948 | if (!ops->display_otr_message(opdata, accountname, | ||
949 | protocol, sender, buf)) { | ||
950 | edata.ignore_message = 1; | ||
951 | } | ||
952 | } | ||
953 | if (edata.ignore_message != 1) { | ||
954 | *newmessagep = buf; | ||
955 | edata.ignore_message = 0; | ||
956 | } else { | ||
957 | free(buf); | ||
958 | } | ||
959 | } | ||
960 | format = "?OTR Error: You sent encrypted " | ||
961 | "data to %s, who wasn't expecting it."; | ||
962 | if (otrl_api_version >= 0x00030100 && | ||
963 | ops->account_name) { | ||
964 | displayaccountname = ops->account_name(opdata, | ||
965 | context->accountname, protocol); | ||
966 | } else { | ||
967 | displayaccountname = NULL; | ||
968 | } | ||
969 | buf = malloc(strlen(format) + strlen(displayaccountname ? | ||
970 | displayaccountname : context->accountname) | ||
971 | - 1); | ||
972 | if (buf) { | ||
973 | sprintf(buf, format, displayaccountname ? | ||
974 | displayaccountname : context->accountname); | ||
975 | if (ops->inject_message) { | ||
976 | ops->inject_message(opdata, accountname, protocol, | ||
977 | sender, buf); | ||
978 | } | ||
979 | free(buf); | ||
980 | } | ||
981 | if (displayaccountname && otrl_api_version >= 0x00030100 && | ||
982 | ops->account_name_free) { | ||
983 | ops->account_name_free(opdata, displayaccountname); | ||
984 | } | ||
985 | |||
986 | break; | ||
987 | |||
988 | case OTRL_MSGSTATE_ENCRYPTED: | ||
989 | err = otrl_proto_accept_data(&plaintext, &tlvs, context, | ||
990 | message, &flags); | ||
991 | if (err) { | ||
992 | int is_conflict = | ||
993 | (gpg_err_code(err) == GPG_ERR_CONFLICT); | ||
994 | if ((flags & OTRL_MSGFLAGS_IGNORE_UNREADABLE)) { | ||
995 | edata.ignore_message = 1; | ||
996 | break; | ||
997 | }/* | ||
998 | format = is_conflict ? "We received an unreadable " | ||
999 | "encrypted message from %s." : | ||
1000 | "We received a malformed data message from %s."; | ||
1001 | buf = malloc(strlen(format) + strlen(sender) - 1); | ||
1002 | if (buf) { | ||
1003 | sprintf(buf, format, sender); | ||
1004 | if ((!(ops->display_otr_message) || | ||
1005 | ops->display_otr_message(opdata, | ||
1006 | accountname, protocol, sender, | ||
1007 | buf)) && ops->notify) { | ||
1008 | ops->notify(opdata, OTRL_NOTIFY_ERROR, | ||
1009 | accountname, protocol, sender, | ||
1010 | "OTR Error", buf, NULL); | ||
1011 | } | ||
1012 | free(buf); | ||
1013 | }*/ | ||
1014 | if (ops->inject_message) { | ||
1015 | ops->inject_message(opdata, accountname, protocol, | ||
1016 | sender, is_conflict ? "?OTR Error: " | ||
1017 | "You sent an unreadable " | ||
1018 | "message. It has been resent." : | ||
1019 | "?OTR Error: You sent " | ||
1020 | "a malformed message, it has been resent."); | ||
1021 | } | ||
1022 | edata.ignore_message = 1; | ||
1023 | break; | ||
1024 | } | ||
1025 | |||
1026 | /* If the other side told us he's disconnected his | ||
1027 | * private connection, make a note of that so we | ||
1028 | * don't try sending anything else to him. */ | ||
1029 | if (otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED)) { | ||
1030 | otrl_context_force_finished(context); | ||
1031 | } | ||
1032 | |||
1033 | /* If TLVs contain SMP data, process it */ | ||
1034 | nextMsg = context->smstate->nextExpected; | ||
1035 | tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q); | ||
1036 | if (tlv && nextMsg == OTRL_SMP_EXPECT1) { | ||
1037 | /* We can only do the verification half now. | ||
1038 | * We must wait for the secret to be entered | ||
1039 | * to continue. */ | ||
1040 | char *question = (char *)tlv->data; | ||
1041 | char *qend = memchr(question, '\0', tlv->len - 1); | ||
1042 | size_t qlen = qend ? (qend - question + 1) : tlv->len; | ||
1043 | otrl_sm_step2a(context->smstate, tlv->data + qlen, | ||
1044 | tlv->len - qlen, 1); | ||
1045 | } | ||
1046 | tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1); | ||
1047 | if (tlv && nextMsg == OTRL_SMP_EXPECT1) { | ||
1048 | /* We can only do the verification half now. | ||
1049 | * We must wait for the secret to be entered | ||
1050 | * to continue. */ | ||
1051 | otrl_sm_step2a(context->smstate, tlv->data, tlv->len, | ||
1052 | 0); | ||
1053 | } | ||
1054 | tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2); | ||
1055 | if (tlv && nextMsg == OTRL_SMP_EXPECT2) { | ||
1056 | unsigned char* nextmsg; | ||
1057 | int nextmsglen; | ||
1058 | OtrlTLV *sendtlv; | ||
1059 | char *sendsmp; | ||
1060 | otrl_sm_step3(context->smstate, tlv->data, tlv->len, | ||
1061 | &nextmsg, &nextmsglen); | ||
1062 | |||
1063 | if (context->smstate->sm_prog_state != | ||
1064 | OTRL_SMP_PROG_CHEATED) { | ||
1065 | /* Send msg with next smp msg content */ | ||
1066 | sendtlv = otrl_tlv_new(OTRL_TLV_SMP3, nextmsglen, | ||
1067 | nextmsg); | ||
1068 | err = otrl_proto_create_data(&sendsmp, | ||
1069 | context, "", sendtlv, | ||
1070 | OTRL_MSGFLAGS_IGNORE_UNREADABLE); | ||
1071 | if (!err) { | ||
1072 | err = otrl_message_fragment_and_send(ops, | ||
1073 | opdata, context, sendsmp, | ||
1074 | OTRL_FRAGMENT_SEND_ALL, NULL); | ||
1075 | } | ||
1076 | free(sendsmp); | ||
1077 | otrl_tlv_free(sendtlv); | ||
1078 | } | ||
1079 | free(nextmsg); | ||
1080 | } | ||
1081 | tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3); | ||
1082 | if (tlv && nextMsg == OTRL_SMP_EXPECT3) { | ||
1083 | unsigned char* nextmsg; | ||
1084 | int nextmsglen; | ||
1085 | OtrlTLV *sendtlv; | ||
1086 | char *sendsmp; | ||
1087 | err = otrl_sm_step4(context->smstate, tlv->data, | ||
1088 | tlv->len, &nextmsg, &nextmsglen); | ||
1089 | /* Set trust level based on result */ | ||
1090 | if (context->smstate->received_question == 0) { | ||
1091 | set_smp_trust(ops, opdata, context, | ||
1092 | (err == gcry_error(GPG_ERR_NO_ERROR))); | ||
1093 | } | ||
1094 | |||
1095 | if (context->smstate->sm_prog_state != | ||
1096 | OTRL_SMP_PROG_CHEATED) { | ||
1097 | /* Send msg with next smp msg content */ | ||
1098 | sendtlv = otrl_tlv_new(OTRL_TLV_SMP4, nextmsglen, | ||
1099 | nextmsg); | ||
1100 | err = otrl_proto_create_data(&sendsmp, | ||
1101 | context, "", sendtlv, | ||
1102 | OTRL_MSGFLAGS_IGNORE_UNREADABLE); | ||
1103 | if (!err) { | ||
1104 | err = otrl_message_fragment_and_send(ops, | ||
1105 | opdata, context, sendsmp, | ||
1106 | OTRL_FRAGMENT_SEND_ALL, NULL); | ||
1107 | } | ||
1108 | free(sendsmp); | ||
1109 | otrl_tlv_free(sendtlv); | ||
1110 | } | ||
1111 | free(nextmsg); | ||
1112 | } | ||
1113 | tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4); | ||
1114 | if (tlv && nextMsg == OTRL_SMP_EXPECT4) { | ||
1115 | err = otrl_sm_step5(context->smstate, tlv->data, | ||
1116 | tlv->len); | ||
1117 | /* Set trust level based on result */ | ||
1118 | set_smp_trust(ops, opdata, context, | ||
1119 | (err == gcry_error(GPG_ERR_NO_ERROR))); | ||
1120 | } | ||
1121 | tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT); | ||
1122 | if (tlv) { | ||
1123 | context->smstate->nextExpected = OTRL_SMP_EXPECT1; | ||
1124 | } | ||
1125 | if (plaintext[0] == '\0') { | ||
1126 | /* If it's a heartbeat (an empty message), don't | ||
1127 | * display it to the user, but log a debug message. */ | ||
1128 | format = "Heartbeat received from %s.\n"; | ||
1129 | buf = malloc(strlen(format) + strlen(sender) - 1); | ||
1130 | if (buf) { | ||
1131 | sprintf(buf, format, sender); | ||
1132 | if (ops->log_message) { | ||
1133 | ops->log_message(opdata, buf); | ||
1134 | } | ||
1135 | free(buf); | ||
1136 | } | ||
1137 | edata.ignore_message = 1; | ||
1138 | } else if (edata.ignore_message == 0 && | ||
1139 | context->their_keyid > 0) { | ||
1140 | /* If it's *not* a heartbeat, and we haven't | ||
1141 | * sent anything in a while, also send a | ||
1142 | * heartbeat. */ | ||
1143 | time_t now = time(NULL); | ||
1144 | if (context->lastsent < (now - HEARTBEAT_INTERVAL)) { | ||
1145 | char *heartbeat; | ||
1146 | |||
1147 | /* Create the heartbeat message */ | ||
1148 | err = otrl_proto_create_data(&heartbeat, | ||
1149 | context, "", NULL, | ||
1150 | OTRL_MSGFLAGS_IGNORE_UNREADABLE); | ||
1151 | if (!err) { | ||
1152 | /* Send it, and log a debug message */ | ||
1153 | if (ops->inject_message) { | ||
1154 | ops->inject_message(opdata, accountname, | ||
1155 | protocol, sender, heartbeat); | ||
1156 | } | ||
1157 | free(heartbeat); | ||
1158 | |||
1159 | context->lastsent = now; | ||
1160 | |||
1161 | /* Log a debug message */ | ||
1162 | format = "Heartbeat sent to %s.\n"; | ||
1163 | buf = malloc(strlen(format) + strlen(sender) | ||
1164 | - 1); | ||
1165 | if (buf) { | ||
1166 | sprintf(buf, format, sender); | ||
1167 | if (ops->log_message) { | ||
1168 | ops->log_message(opdata, buf); | ||
1169 | } | ||
1170 | free(buf); | ||
1171 | } | ||
1172 | } | ||
1173 | } | ||
1174 | } | ||
1175 | |||
1176 | /* Return the TLVs even if ignore_message == 1 so | ||
1177 | * that we can attach TLVs to heartbeats. */ | ||
1178 | if (tlvsp) { | ||
1179 | *tlvsp = tlvs; | ||
1180 | } else { | ||
1181 | otrl_tlv_free(tlvs); | ||
1182 | } | ||
1183 | |||
1184 | if (edata.ignore_message != 1) { | ||
1185 | *newmessagep = plaintext; | ||
1186 | edata.ignore_message = 0; | ||
1187 | } else { | ||
1188 | free(plaintext); | ||
1189 | } | ||
1190 | break; | ||
1191 | } | ||
1192 | break; | ||
1193 | |||
1194 | case OTRL_MSGTYPE_ERROR: | ||
1195 | if ((policy & OTRL_POLICY_ERROR_START_AKE)) { | ||
1196 | char *msgtosend = otrl_proto_default_query_msg( | ||
1197 | context->accountname, policy); | ||
1198 | if (msgtosend && ops->inject_message) { | ||
1199 | ops->inject_message(opdata, context->accountname, | ||
1200 | context->protocol, context->username, | ||
1201 | msgtosend); | ||
1202 | } | ||
1203 | free(msgtosend); | ||
1204 | } | ||
1205 | |||
1206 | if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { | ||
1207 | /* Mark the last message we sent as eligible for | ||
1208 | * retransmission */ | ||
1209 | context->may_retransmit = 1; | ||
1210 | } | ||
1211 | |||
1212 | /* In any event, display the error message, with the | ||
1213 | * display_otr_message callback, if possible */ | ||
1214 | if (ops->display_otr_message) { | ||
1215 | const char *otrerror = strstr(message, "?OTR Error:"); | ||
1216 | if (otrerror) { | ||
1217 | /* Skip the leading '?' */ | ||
1218 | ++otrerror; | ||
1219 | } else { | ||
1220 | otrerror = message; | ||
1221 | } | ||
1222 | if (!ops->display_otr_message(opdata, accountname, protocol, | ||
1223 | sender, otrerror)) { | ||
1224 | edata.ignore_message = 1; | ||
1225 | } | ||
1226 | } | ||
1227 | break; | ||
1228 | |||
1229 | case OTRL_MSGTYPE_TAGGEDPLAINTEXT: | ||
1230 | /* Strip the tag from the message */ | ||
1231 | bestversion = otrl_proto_whitespace_bestversion(message, | ||
1232 | &startwhite, &endwhite, policy); | ||
1233 | if (startwhite && endwhite) { | ||
1234 | size_t restlen = strlen(endwhite); | ||
1235 | char *strippedmsg = strdup(message); | ||
1236 | |||
1237 | if (strippedmsg) { | ||
1238 | memmove(strippedmsg + (startwhite - message), | ||
1239 | strippedmsg + (endwhite - message), restlen+1); | ||
1240 | *newmessagep = strippedmsg; | ||
1241 | edata.ignore_message = 0; | ||
1242 | } | ||
1243 | } | ||
1244 | if (bestversion && context->msgstate != OTRL_MSGSTATE_ENCRYPTED | ||
1245 | && (policy & OTRL_POLICY_WHITESPACE_START_AKE)) { | ||
1246 | switch(bestversion) { | ||
1247 | case 2: | ||
1248 | err = otrl_auth_start_v2(&(context->auth)); | ||
1249 | send_or_error_auth(ops, opdata, err, context); | ||
1250 | break; | ||
1251 | case 1: | ||
1252 | /* Get our private key */ | ||
1253 | privkey = otrl_privkey_find(us, context->accountname, | ||
1254 | context->protocol); | ||
1255 | if (privkey == NULL) { | ||
1256 | /* We've got no private key! */ | ||
1257 | if (ops->create_privkey) { | ||
1258 | ops->create_privkey(opdata, | ||
1259 | context->accountname, | ||
1260 | context->protocol); | ||
1261 | privkey = otrl_privkey_find(us, | ||
1262 | context->accountname, | ||
1263 | context->protocol); | ||
1264 | } | ||
1265 | } | ||
1266 | if (privkey) { | ||
1267 | err = otrl_auth_start_v1(&(context->auth), NULL, 0, | ||
1268 | privkey); | ||
1269 | send_or_error_auth(ops, opdata, err, context); | ||
1270 | } | ||
1271 | break; | ||
1272 | default: | ||
1273 | /* Don't start the AKE */ | ||
1274 | break; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | /* FALLTHROUGH */ | ||
1279 | case OTRL_MSGTYPE_NOTOTR: | ||
1280 | if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT || | ||
1281 | (policy & OTRL_POLICY_REQUIRE_ENCRYPTION)) { | ||
1282 | /* Not fine. Let the user know. */ | ||
1283 | |||
1284 | /* Don't use g_strdup_printf here, because someone | ||
1285 | * (not us) is going to free() the *message pointer, | ||
1286 | * not g_free() it. */ | ||
1287 | const char *plainmsg = (*newmessagep) ? *newmessagep : message; | ||
1288 | const char *format = "NOT encrypted: [%s]"; | ||
1289 | char *buf = 0; | ||
1290 | if (policy & OTRL_POLICY_REQUIRE_ENCRYPTION) { | ||
1291 | format = "%s sent a message that was NOT encrypted."; | ||
1292 | buf = malloc(strlen(format) + strlen(context->username) | ||
1293 | + strlen(plainmsg) - 1); | ||
1294 | /* Remove "%s", add username + message + '\0' */ | ||
1295 | } | ||
1296 | else | ||
1297 | { | ||
1298 | buf = malloc(strlen(format) + strlen(context->username) | ||
1299 | + strlen(plainmsg) - 3); | ||
1300 | /* Remove "%s%s", add username + message + '\0' */ | ||
1301 | } | ||
1302 | if (buf) { | ||
1303 | sprintf(buf, format, plainmsg); | ||
1304 | if (ops->display_otr_message) { | ||
1305 | if (!ops->display_otr_message(opdata, accountname, | ||
1306 | protocol, sender, buf)) { | ||
1307 | free(*newmessagep); | ||
1308 | *newmessagep = NULL; | ||
1309 | edata.ignore_message = 1; | ||
1310 | } | ||
1311 | } | ||
1312 | if (edata.ignore_message != 1) { | ||
1313 | free(*newmessagep); | ||
1314 | *newmessagep = buf; | ||
1315 | edata.ignore_message = 0; | ||
1316 | } else { | ||
1317 | free(buf); | ||
1318 | } | ||
1319 | } | ||
1320 | } | ||
1321 | break; | ||
1322 | |||
1323 | case OTRL_MSGTYPE_UNKNOWN: | ||
1324 | /* We received an OTR message we didn't recognize. Ignore | ||
1325 | * it, but make a log entry. */ | ||
1326 | if (ops->log_message) { | ||
1327 | const char *format = "Unrecognized OTR message received " | ||
1328 | "from %s.\n"; | ||
1329 | char *buf = malloc(strlen(format) + strlen(sender) - 1); | ||
1330 | if (buf) { | ||
1331 | sprintf(buf, format, sender); | ||
1332 | ops->log_message(opdata, buf); | ||
1333 | free(buf); | ||
1334 | } | ||
1335 | } | ||
1336 | if (edata.ignore_message == -1) edata.ignore_message = 1; | ||
1337 | break; | ||
1338 | } | ||
1339 | |||
1340 | /* If we reassembled a fragmented message, we need to free the | ||
1341 | * allocated memory now. */ | ||
1342 | if (fragment_assembled) { | ||
1343 | free(unfragmessage); | ||
1344 | } | ||
1345 | |||
1346 | if (edata.ignore_message == -1) edata.ignore_message = 0; | ||
1347 | return edata.ignore_message; | ||
1348 | } | ||
1349 | |||
1350 | /* Send a message to the network, fragmenting first if necessary. | ||
1351 | * All messages to be sent to the network should go through this | ||
1352 | * method immediately before they are sent, ie after encryption. */ | ||
1353 | gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops, | ||
1354 | void *opdata, ConnContext *context, const char *message, | ||
1355 | OtrlFragmentPolicy fragPolicy, char **returnFragment) | ||
1356 | { | ||
1357 | int mms = 0; | ||
1358 | if (message && ops->inject_message) { | ||
1359 | int msglen; | ||
1360 | |||
1361 | if (otrl_api_version >= 0x030100 && ops->max_message_size) { | ||
1362 | mms = ops->max_message_size(opdata, context); | ||
1363 | } | ||
1364 | msglen = strlen(message); | ||
1365 | |||
1366 | /* Don't incur overhead of fragmentation unless necessary */ | ||
1367 | if(mms != 0 && msglen > mms) { | ||
1368 | char **fragments; | ||
1369 | gcry_error_t err; | ||
1370 | int i; | ||
1371 | int fragment_count = ((msglen - 1) / (mms -19)) + 1; | ||
1372 | /* like ceil(msglen/(mms - 19)) */ | ||
1373 | |||
1374 | err = otrl_proto_fragment_create(mms, fragment_count, &fragments, | ||
1375 | message); | ||
1376 | if (err) { | ||
1377 | return err; | ||
1378 | } | ||
1379 | |||
1380 | /* Determine which fragments to send and which to return | ||
1381 | * based on given Fragment Policy. If the first fragment | ||
1382 | * should be returned instead of sent, store it. */ | ||
1383 | if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_FIRST) { | ||
1384 | *returnFragment = strdup(fragments[0]); | ||
1385 | } else { | ||
1386 | ops->inject_message(opdata, context->accountname, | ||
1387 | context->protocol, context->username, fragments[0]); | ||
1388 | } | ||
1389 | for (i=1; i<fragment_count-1; i++) { | ||
1390 | ops->inject_message(opdata, context->accountname, | ||
1391 | context->protocol, context->username, fragments[i]); | ||
1392 | } | ||
1393 | /* If the last fragment should be stored instead of sent, | ||
1394 | * store it */ | ||
1395 | if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_LAST) { | ||
1396 | *returnFragment = strdup(fragments[fragment_count-1]); | ||
1397 | } else { | ||
1398 | ops->inject_message(opdata, context->accountname, | ||
1399 | context->protocol, context->username, fragments[fragment_count-1]); | ||
1400 | } | ||
1401 | /* Now free all fragment memory */ | ||
1402 | otrl_proto_fragment_free(&fragments, fragment_count); | ||
1403 | |||
1404 | } else { | ||
1405 | /* No fragmentation necessary */ | ||
1406 | if (fragPolicy == OTRL_FRAGMENT_SEND_ALL) { | ||
1407 | ops->inject_message(opdata, context->accountname, | ||
1408 | context->protocol, context->username, message); | ||
1409 | } else { | ||
1410 | /* Copy and return the entire given message. */ | ||
1411 | int l = strlen(message) + 1; | ||
1412 | *returnFragment = malloc(sizeof(char)*l); | ||
1413 | strcpy(*returnFragment, message); | ||
1414 | } | ||
1415 | } | ||
1416 | } | ||
1417 | return gcry_error(GPG_ERR_NO_ERROR); | ||
1418 | } | ||
1419 | |||
1420 | /* Put a connection into the PLAINTEXT state, first sending the | ||
1421 | * other side a notice that we're doing so if we're currently ENCRYPTED, | ||
1422 | * and we think he's logged in. */ | ||
1423 | void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
1424 | void *opdata, const char *accountname, const char *protocol, | ||
1425 | const char *username) | ||
1426 | { | ||
1427 | ConnContext *context = otrl_context_find(us, username, accountname, | ||
1428 | protocol, 0, NULL, NULL, NULL); | ||
1429 | |||
1430 | if (!context) return; | ||
1431 | |||
1432 | if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED && | ||
1433 | context->their_keyid > 0 && | ||
1434 | ops->is_logged_in && | ||
1435 | ops->is_logged_in(opdata, accountname, protocol, username) == 1) { | ||
1436 | if (ops->inject_message) { | ||
1437 | char *encmsg = NULL; | ||
1438 | gcry_error_t err; | ||
1439 | OtrlTLV *tlv = otrl_tlv_new(OTRL_TLV_DISCONNECTED, 0, NULL); | ||
1440 | |||
1441 | err = otrl_proto_create_data(&encmsg, context, "", tlv, | ||
1442 | OTRL_MSGFLAGS_IGNORE_UNREADABLE); | ||
1443 | if (!err) { | ||
1444 | ops->inject_message(opdata, accountname, protocol, | ||
1445 | username, encmsg); | ||
1446 | } | ||
1447 | free(encmsg); | ||
1448 | } | ||
1449 | } | ||
1450 | |||
1451 | otrl_context_force_plaintext(context); | ||
1452 | if (ops->update_context_list) { | ||
1453 | ops->update_context_list(opdata); | ||
1454 | } | ||
1455 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/message.h b/linden/indra/libotr/libotr-3.2.0/src/message.h new file mode 100755 index 0000000..e658e9d --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/message.h | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __MESSAGE_H__ | ||
21 | #define __MESSAGE_H__ | ||
22 | |||
23 | typedef enum { | ||
24 | OTRL_NOTIFY_ERROR, | ||
25 | OTRL_NOTIFY_WARNING, | ||
26 | OTRL_NOTIFY_INFO | ||
27 | } OtrlNotifyLevel; | ||
28 | |||
29 | typedef struct s_OtrlMessageAppOps { | ||
30 | /* Return the OTR policy for the given context. */ | ||
31 | OtrlPolicy (*policy)(void *opdata, ConnContext *context); | ||
32 | |||
33 | /* Create a private key for the given accountname/protocol if | ||
34 | * desired. */ | ||
35 | void (*create_privkey)(void *opdata, const char *accountname, | ||
36 | const char *protocol); | ||
37 | |||
38 | /* Report whether you think the given user is online. Return 1 if | ||
39 | * you think he is, 0 if you think he isn't, -1 if you're not sure. | ||
40 | * | ||
41 | * If you return 1, messages such as heartbeats or other | ||
42 | * notifications may be sent to the user, which could result in "not | ||
43 | * logged in" errors if you're wrong. */ | ||
44 | int (*is_logged_in)(void *opdata, const char *accountname, | ||
45 | const char *protocol, const char *recipient); | ||
46 | |||
47 | /* Send the given IM to the given recipient from the given | ||
48 | * accountname/protocol. */ | ||
49 | void (*inject_message)(void *opdata, const char *accountname, | ||
50 | const char *protocol, const char *recipient, const char *message); | ||
51 | |||
52 | /* Display a notification message for a particular accountname / | ||
53 | * protocol / username conversation. */ | ||
54 | void (*notify)(void *opdata, OtrlNotifyLevel level, | ||
55 | const char *accountname, const char *protocol, | ||
56 | const char *username, const char *title, | ||
57 | const char *primary, const char *secondary); | ||
58 | |||
59 | /* Display an OTR control message for a particular accountname / | ||
60 | * protocol / username conversation. Return 0 if you are able to | ||
61 | * successfully display it. If you return non-0 (or if this | ||
62 | * function is NULL), the control message will be displayed inline, | ||
63 | * as a received message, or else by using the above notify() | ||
64 | * callback. */ | ||
65 | int (*display_otr_message)(void *opdata, const char *accountname, | ||
66 | const char *protocol, const char *username, const char *msg); | ||
67 | |||
68 | /* When the list of ConnContexts changes (including a change in | ||
69 | * state), this is called so the UI can be updated. */ | ||
70 | void (*update_context_list)(void *opdata); | ||
71 | |||
72 | /* Return a newly allocated string containing a human-friendly name | ||
73 | * for the given protocol id */ | ||
74 | const char *(*protocol_name)(void *opdata, const char *protocol); | ||
75 | |||
76 | /* Deallocate a string allocated by protocol_name */ | ||
77 | void (*protocol_name_free)(void *opdata, const char *protocol_name); | ||
78 | |||
79 | /* A new fingerprint for the given user has been received. */ | ||
80 | void (*new_fingerprint)(void *opdata, OtrlUserState us, | ||
81 | const char *accountname, const char *protocol, | ||
82 | const char *username, unsigned char fingerprint[20]); | ||
83 | |||
84 | /* The list of known fingerprints has changed. Write them to disk. */ | ||
85 | void (*write_fingerprints)(void *opdata); | ||
86 | |||
87 | /* A ConnContext has entered a secure state. */ | ||
88 | void (*gone_secure)(void *opdata, ConnContext *context); | ||
89 | |||
90 | /* A ConnContext has left a secure state. */ | ||
91 | void (*gone_insecure)(void *opdata, ConnContext *context); | ||
92 | |||
93 | /* We have completed an authentication, using the D-H keys we | ||
94 | * already knew. is_reply indicates whether we initiated the AKE. */ | ||
95 | void (*still_secure)(void *opdata, ConnContext *context, int is_reply); | ||
96 | |||
97 | /* Log a message. The passed message will end in "\n". */ | ||
98 | void (*log_message)(void *opdata, const char *message); | ||
99 | |||
100 | /* Find the maximum message size supported by this protocol. */ | ||
101 | int (*max_message_size)(void *opdata, ConnContext *context); | ||
102 | |||
103 | /* Return a newly allocated string containing a human-friendly | ||
104 | * representation for the given account */ | ||
105 | const char *(*account_name)(void *opdata, const char *account, | ||
106 | const char *protocol); | ||
107 | |||
108 | /* Deallocate a string returned by account_name */ | ||
109 | void (*account_name_free)(void *opdata, const char *account_name); | ||
110 | |||
111 | } OtrlMessageAppOps; | ||
112 | |||
113 | /* Deallocate a message allocated by other otrl_message_* routines. */ | ||
114 | void otrl_message_free(char *message); | ||
115 | |||
116 | /* Handle a message about to be sent to the network. It is safe to pass | ||
117 | * all messages about to be sent to this routine. add_appdata is a | ||
118 | * function that will be called in the event that a new ConnContext is | ||
119 | * created. It will be passed the data that you supplied, as well as a | ||
120 | * pointer to the new ConnContext. You can use this to add | ||
121 | * application-specific information to the ConnContext using the | ||
122 | * "context->app" field, for example. If you don't need to do this, you | ||
123 | * can pass NULL for the last two arguments of otrl_message_sending. | ||
124 | * | ||
125 | * tlvs is a chain of OtrlTLVs to append to the private message. It is | ||
126 | * usually correct to just pass NULL here. | ||
127 | * | ||
128 | * If this routine returns non-zero, then the library tried to encrypt | ||
129 | * the message, but for some reason failed. DO NOT send the message in | ||
130 | * the clear in that case. | ||
131 | * | ||
132 | * If *messagep gets set by the call to something non-NULL, then you | ||
133 | * should replace your message with the contents of *messagep, and | ||
134 | * send that instead. Call otrl_message_free(*messagep) when you're | ||
135 | * done with it. */ | ||
136 | gcry_error_t otrl_message_sending(OtrlUserState us, | ||
137 | const OtrlMessageAppOps *ops, | ||
138 | void *opdata, const char *accountname, const char *protocol, | ||
139 | const char *recipient, const char *message, OtrlTLV *tlvs, | ||
140 | char **messagep, | ||
141 | void (*add_appdata)(void *data, ConnContext *context), | ||
142 | void *data); | ||
143 | |||
144 | /* Handle a message just received from the network. It is safe to pass | ||
145 | * all received messages to this routine. add_appdata is a function | ||
146 | * that will be called in the event that a new ConnContext is created. | ||
147 | * It will be passed the data that you supplied, as well as | ||
148 | * a pointer to the new ConnContext. You can use this to add | ||
149 | * application-specific information to the ConnContext using the | ||
150 | * "context->app" field, for example. If you don't need to do this, you | ||
151 | * can pass NULL for the last two arguments of otrl_message_receiving. | ||
152 | * | ||
153 | * If otrl_message_receiving returns 1, then the message you received | ||
154 | * was an internal protocol message, and no message should be delivered | ||
155 | * to the user. | ||
156 | * | ||
157 | * If it returns 0, then check if *messagep was set to non-NULL. If | ||
158 | * so, replace the received message with the contents of *messagep, and | ||
159 | * deliver that to the user instead. You must call | ||
160 | * otrl_message_free(*messagep) when you're done with it. If tlvsp is | ||
161 | * non-NULL, *tlvsp will be set to a chain of any TLVs that were | ||
162 | * transmitted along with this message. You must call | ||
163 | * otrl_tlv_free(*tlvsp) when you're done with those. | ||
164 | * | ||
165 | * If otrl_message_receiving returns 0 and *messagep is NULL, then this | ||
166 | * was an ordinary, non-OTR message, which should just be delivered to | ||
167 | * the user without modification. */ | ||
168 | int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
169 | void *opdata, const char *accountname, const char *protocol, | ||
170 | const char *sender, const char *message, char **newmessagep, | ||
171 | OtrlTLV **tlvsp, | ||
172 | void (*add_appdata)(void *data, ConnContext *context), | ||
173 | void *data); | ||
174 | |||
175 | /* Send a message to the network, fragmenting first if necessary. | ||
176 | * All messages to be sent to the network should go through this | ||
177 | * method immediately before they are sent, ie after encryption. */ | ||
178 | gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops, | ||
179 | void *opdata, ConnContext *context, const char *message, | ||
180 | OtrlFragmentPolicy fragPolicy, char **returnFragment); | ||
181 | |||
182 | /* Put a connection into the PLAINTEXT state, first sending the | ||
183 | * other side a notice that we're doing so if we're currently ENCRYPTED, | ||
184 | * and we think he's logged in. */ | ||
185 | void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
186 | void *opdata, const char *accountname, const char *protocol, | ||
187 | const char *username); | ||
188 | |||
189 | /* Initiate the Socialist Millionaires' Protocol */ | ||
190 | void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
191 | void *opdata, ConnContext *context, const unsigned char *secret, | ||
192 | size_t secretlen); | ||
193 | |||
194 | /* Initiate the Socialist Millionaires' Protocol and send a prompt | ||
195 | * question to the buddy */ | ||
196 | void otrl_message_initiate_smp_q(OtrlUserState us, | ||
197 | const OtrlMessageAppOps *ops, void *opdata, ConnContext *context, | ||
198 | const char *question, const unsigned char *secret, size_t secretlen); | ||
199 | |||
200 | /* Respond to a buddy initiating the Socialist Millionaires' Protocol */ | ||
201 | void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
202 | void *opdata, ConnContext *context, const unsigned char *secret, | ||
203 | size_t secretlen); | ||
204 | |||
205 | /* Abort the SMP. Called when an unexpected SMP message breaks the | ||
206 | * normal flow. */ | ||
207 | void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops, | ||
208 | void *opdata, ConnContext *context); | ||
209 | |||
210 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/privkey-t.h b/linden/indra/libotr/libotr-3.2.0/src/privkey-t.h new file mode 100755 index 0000000..3421b8b --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/privkey-t.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __PRIVKEY_T_H__ | ||
21 | #define __PRIVKEY_T_H__ | ||
22 | |||
23 | #include <gcrypt.h> | ||
24 | |||
25 | typedef struct s_OtrlPrivKey { | ||
26 | struct s_OtrlPrivKey *next; | ||
27 | struct s_OtrlPrivKey **tous; | ||
28 | |||
29 | char *accountname; | ||
30 | char *protocol; | ||
31 | unsigned short pubkey_type; | ||
32 | gcry_sexp_t privkey; | ||
33 | unsigned char *pubkey_data; | ||
34 | size_t pubkey_datalen; | ||
35 | } OtrlPrivKey; | ||
36 | |||
37 | #define OTRL_PUBKEY_TYPE_DSA 0x0000 | ||
38 | |||
39 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/privkey.c b/linden/indra/libotr/libotr-3.2.0/src/privkey.c new file mode 100755 index 0000000..aacecd5 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/privkey.c | |||
@@ -0,0 +1,745 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* system headers */ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <errno.h> | ||
24 | #include <sys/stat.h> | ||
25 | |||
26 | /* libgcrypt headers */ | ||
27 | #include <gcrypt.h> | ||
28 | |||
29 | /* libotr headers */ | ||
30 | #include "privkey.h" | ||
31 | #include "serial.h" | ||
32 | |||
33 | /* Convert a 20-byte hash value to a 45-byte human-readable value */ | ||
34 | void otrl_privkey_hash_to_human(char human[45], const unsigned char hash[20]) | ||
35 | { | ||
36 | int word, byte; | ||
37 | char *p = human; | ||
38 | |||
39 | for(word=0; word<5; ++word) { | ||
40 | for(byte=0; byte<4; ++byte) { | ||
41 | sprintf(p, "%02X", hash[word*4+byte]); | ||
42 | p += 2; | ||
43 | } | ||
44 | *(p++) = ' '; | ||
45 | } | ||
46 | /* Change that last ' ' to a '\0' */ | ||
47 | --p; | ||
48 | *p = '\0'; | ||
49 | } | ||
50 | |||
51 | /* Calculate a human-readable hash of our DSA public key. Return it in | ||
52 | * the passed fingerprint buffer. Return NULL on error, or a pointer to | ||
53 | * the given buffer on success. */ | ||
54 | char *otrl_privkey_fingerprint(OtrlUserState us, char fingerprint[45], | ||
55 | const char *accountname, const char *protocol) | ||
56 | { | ||
57 | unsigned char hash[20]; | ||
58 | OtrlPrivKey *p = otrl_privkey_find(us, accountname, protocol); | ||
59 | |||
60 | if (p) { | ||
61 | /* Calculate the hash */ | ||
62 | gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data, | ||
63 | p->pubkey_datalen); | ||
64 | |||
65 | /* Now convert it to a human-readable format */ | ||
66 | otrl_privkey_hash_to_human(fingerprint, hash); | ||
67 | } else { | ||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | return fingerprint; | ||
72 | } | ||
73 | |||
74 | /* Calculate a raw hash of our DSA public key. Return it in the passed | ||
75 | * fingerprint buffer. Return NULL on error, or a pointer to the given | ||
76 | * buffer on success. */ | ||
77 | unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us, | ||
78 | unsigned char hash[20], const char *accountname, const char *protocol) | ||
79 | { | ||
80 | OtrlPrivKey *p = otrl_privkey_find(us, accountname, protocol); | ||
81 | |||
82 | if (p) { | ||
83 | /* Calculate the hash */ | ||
84 | gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data, | ||
85 | p->pubkey_datalen); | ||
86 | } else { | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | return hash; | ||
91 | } | ||
92 | |||
93 | /* Create a public key block from a private key */ | ||
94 | static gcry_error_t make_pubkey(unsigned char **pubbufp, size_t *publenp, | ||
95 | gcry_sexp_t privkey) | ||
96 | { | ||
97 | gcry_mpi_t p,q,g,y; | ||
98 | gcry_sexp_t dsas,ps,qs,gs,ys; | ||
99 | size_t np,nq,ng,ny; | ||
100 | enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
101 | unsigned char *bufp; | ||
102 | size_t lenp; | ||
103 | |||
104 | *pubbufp = NULL; | ||
105 | *publenp = 0; | ||
106 | |||
107 | /* Extract the public parameters */ | ||
108 | dsas = gcry_sexp_find_token(privkey, "dsa", 0); | ||
109 | if (dsas == NULL) { | ||
110 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
111 | } | ||
112 | ps = gcry_sexp_find_token(dsas, "p", 0); | ||
113 | qs = gcry_sexp_find_token(dsas, "q", 0); | ||
114 | gs = gcry_sexp_find_token(dsas, "g", 0); | ||
115 | ys = gcry_sexp_find_token(dsas, "y", 0); | ||
116 | gcry_sexp_release(dsas); | ||
117 | if (!ps || !qs || !gs || !ys) { | ||
118 | gcry_sexp_release(ps); | ||
119 | gcry_sexp_release(qs); | ||
120 | gcry_sexp_release(gs); | ||
121 | gcry_sexp_release(ys); | ||
122 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
123 | } | ||
124 | p = gcry_sexp_nth_mpi(ps, 1, GCRYMPI_FMT_USG); | ||
125 | gcry_sexp_release(ps); | ||
126 | q = gcry_sexp_nth_mpi(qs, 1, GCRYMPI_FMT_USG); | ||
127 | gcry_sexp_release(qs); | ||
128 | g = gcry_sexp_nth_mpi(gs, 1, GCRYMPI_FMT_USG); | ||
129 | gcry_sexp_release(gs); | ||
130 | y = gcry_sexp_nth_mpi(ys, 1, GCRYMPI_FMT_USG); | ||
131 | gcry_sexp_release(ys); | ||
132 | if (!p || !q || !g || !y) { | ||
133 | gcry_mpi_release(p); | ||
134 | gcry_mpi_release(q); | ||
135 | gcry_mpi_release(g); | ||
136 | gcry_mpi_release(y); | ||
137 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
138 | } | ||
139 | |||
140 | *publenp = 0; | ||
141 | gcry_mpi_print(format, NULL, 0, &np, p); | ||
142 | *publenp += np + 4; | ||
143 | gcry_mpi_print(format, NULL, 0, &nq, q); | ||
144 | *publenp += nq + 4; | ||
145 | gcry_mpi_print(format, NULL, 0, &ng, g); | ||
146 | *publenp += ng + 4; | ||
147 | gcry_mpi_print(format, NULL, 0, &ny, y); | ||
148 | *publenp += ny + 4; | ||
149 | |||
150 | *pubbufp = malloc(*publenp); | ||
151 | if (*pubbufp == NULL) { | ||
152 | gcry_mpi_release(p); | ||
153 | gcry_mpi_release(q); | ||
154 | gcry_mpi_release(g); | ||
155 | gcry_mpi_release(y); | ||
156 | return gcry_error(GPG_ERR_ENOMEM); | ||
157 | } | ||
158 | bufp = *pubbufp; | ||
159 | lenp = *publenp; | ||
160 | |||
161 | write_mpi(p,np,"P"); | ||
162 | write_mpi(q,nq,"Q"); | ||
163 | write_mpi(g,ng,"G"); | ||
164 | write_mpi(y,ny,"Y"); | ||
165 | |||
166 | gcry_mpi_release(p); | ||
167 | gcry_mpi_release(q); | ||
168 | gcry_mpi_release(g); | ||
169 | gcry_mpi_release(y); | ||
170 | |||
171 | return gcry_error(GPG_ERR_NO_ERROR); | ||
172 | } | ||
173 | |||
174 | /* Read a sets of private DSA keys from a file on disk into the given | ||
175 | * OtrlUserState. */ | ||
176 | gcry_error_t otrl_privkey_read(OtrlUserState us, const char *filename) | ||
177 | { | ||
178 | FILE *privf; | ||
179 | gcry_error_t err; | ||
180 | |||
181 | /* Open the privkey file. We use rb mode so that on WIN32, fread() | ||
182 | * reads the same number of bytes that fstat() indicates are in the | ||
183 | * file. */ | ||
184 | privf = fopen(filename, "rb"); | ||
185 | if (!privf) { | ||
186 | err = gcry_error_from_errno(errno); | ||
187 | return err; | ||
188 | } | ||
189 | |||
190 | err = otrl_privkey_read_FILEp(us, privf); | ||
191 | |||
192 | fclose(privf); | ||
193 | return err; | ||
194 | } | ||
195 | |||
196 | /* Read a sets of private DSA keys from a FILE* into the given | ||
197 | * OtrlUserState. The FILE* must be open for reading. */ | ||
198 | gcry_error_t otrl_privkey_read_FILEp(OtrlUserState us, FILE *privf) | ||
199 | { | ||
200 | int privfd; | ||
201 | struct stat st; | ||
202 | char *buf; | ||
203 | const char *token; | ||
204 | size_t tokenlen; | ||
205 | gcry_error_t err; | ||
206 | gcry_sexp_t allkeys; | ||
207 | size_t i; | ||
208 | |||
209 | if (!privf) return gcry_error(GPG_ERR_NO_ERROR); | ||
210 | |||
211 | /* Release any old ideas we had about our keys */ | ||
212 | otrl_privkey_forget_all(us); | ||
213 | |||
214 | /* Load the data into a buffer */ | ||
215 | privfd = fileno(privf); | ||
216 | if (fstat(privfd, &st)) { | ||
217 | err = gcry_error_from_errno(errno); | ||
218 | return err; | ||
219 | } | ||
220 | buf = malloc(st.st_size); | ||
221 | if (!buf && st.st_size > 0) { | ||
222 | return gcry_error(GPG_ERR_ENOMEM); | ||
223 | } | ||
224 | if (fread(buf, st.st_size, 1, privf) != 1) { | ||
225 | err = gcry_error_from_errno(errno); | ||
226 | free(buf); | ||
227 | return err; | ||
228 | } | ||
229 | |||
230 | err = gcry_sexp_new(&allkeys, buf, st.st_size, 0); | ||
231 | free(buf); | ||
232 | if (err) { | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | token = gcry_sexp_nth_data(allkeys, 0, &tokenlen); | ||
237 | if (tokenlen != 8 || strncmp(token, "privkeys", 8)) { | ||
238 | gcry_sexp_release(allkeys); | ||
239 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
240 | } | ||
241 | |||
242 | /* Get each account */ | ||
243 | for(i=1; i<((size_t)gcry_sexp_length(allkeys)); ++i) { | ||
244 | gcry_sexp_t names, protos, privs; | ||
245 | char *name, *proto; | ||
246 | gcry_sexp_t accounts; | ||
247 | OtrlPrivKey *p; | ||
248 | |||
249 | /* Get the ith "account" S-exp */ | ||
250 | accounts = gcry_sexp_nth(allkeys, i); | ||
251 | |||
252 | /* It's really an "account" S-exp? */ | ||
253 | token = gcry_sexp_nth_data(accounts, 0, &tokenlen); | ||
254 | if (tokenlen != 7 || strncmp(token, "account", 7)) { | ||
255 | gcry_sexp_release(accounts); | ||
256 | gcry_sexp_release(allkeys); | ||
257 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
258 | } | ||
259 | /* Extract the name, protocol, and privkey S-exps */ | ||
260 | names = gcry_sexp_find_token(accounts, "name", 0); | ||
261 | protos = gcry_sexp_find_token(accounts, "protocol", 0); | ||
262 | privs = gcry_sexp_find_token(accounts, "private-key", 0); | ||
263 | gcry_sexp_release(accounts); | ||
264 | if (!names || !protos || !privs) { | ||
265 | gcry_sexp_release(names); | ||
266 | gcry_sexp_release(protos); | ||
267 | gcry_sexp_release(privs); | ||
268 | gcry_sexp_release(allkeys); | ||
269 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
270 | } | ||
271 | /* Extract the actual name and protocol */ | ||
272 | token = gcry_sexp_nth_data(names, 1, &tokenlen); | ||
273 | if (!token) { | ||
274 | gcry_sexp_release(names); | ||
275 | gcry_sexp_release(protos); | ||
276 | gcry_sexp_release(privs); | ||
277 | gcry_sexp_release(allkeys); | ||
278 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
279 | } | ||
280 | name = malloc(tokenlen + 1); | ||
281 | if (!name) { | ||
282 | gcry_sexp_release(names); | ||
283 | gcry_sexp_release(protos); | ||
284 | gcry_sexp_release(privs); | ||
285 | gcry_sexp_release(allkeys); | ||
286 | return gcry_error(GPG_ERR_ENOMEM); | ||
287 | } | ||
288 | memmove(name, token, tokenlen); | ||
289 | name[tokenlen] = '\0'; | ||
290 | gcry_sexp_release(names); | ||
291 | |||
292 | token = gcry_sexp_nth_data(protos, 1, &tokenlen); | ||
293 | if (!token) { | ||
294 | free(name); | ||
295 | gcry_sexp_release(protos); | ||
296 | gcry_sexp_release(privs); | ||
297 | gcry_sexp_release(allkeys); | ||
298 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
299 | } | ||
300 | proto = malloc(tokenlen + 1); | ||
301 | if (!proto) { | ||
302 | free(name); | ||
303 | gcry_sexp_release(protos); | ||
304 | gcry_sexp_release(privs); | ||
305 | gcry_sexp_release(allkeys); | ||
306 | return gcry_error(GPG_ERR_ENOMEM); | ||
307 | } | ||
308 | memmove(proto, token, tokenlen); | ||
309 | proto[tokenlen] = '\0'; | ||
310 | gcry_sexp_release(protos); | ||
311 | |||
312 | /* Make a new OtrlPrivKey entry */ | ||
313 | p = malloc(sizeof(*p)); | ||
314 | if (!p) { | ||
315 | free(name); | ||
316 | free(proto); | ||
317 | gcry_sexp_release(privs); | ||
318 | gcry_sexp_release(allkeys); | ||
319 | return gcry_error(GPG_ERR_ENOMEM); | ||
320 | } | ||
321 | |||
322 | /* Fill it in and link it up */ | ||
323 | p->accountname = name; | ||
324 | p->protocol = proto; | ||
325 | p->pubkey_type = OTRL_PUBKEY_TYPE_DSA; | ||
326 | p->privkey = privs; | ||
327 | p->next = us->privkey_root; | ||
328 | if (p->next) { | ||
329 | p->next->tous = &(p->next); | ||
330 | } | ||
331 | p->tous = &(us->privkey_root); | ||
332 | us->privkey_root = p; | ||
333 | err = make_pubkey(&(p->pubkey_data), &(p->pubkey_datalen), p->privkey); | ||
334 | if (err) { | ||
335 | gcry_sexp_release(allkeys); | ||
336 | otrl_privkey_forget(p); | ||
337 | return gcry_error(GPG_ERR_UNUSABLE_SECKEY); | ||
338 | } | ||
339 | } | ||
340 | gcry_sexp_release(allkeys); | ||
341 | |||
342 | return gcry_error(GPG_ERR_NO_ERROR); | ||
343 | } | ||
344 | |||
345 | static gcry_error_t sexp_write(FILE *privf, gcry_sexp_t sexp) | ||
346 | { | ||
347 | size_t buflen; | ||
348 | char *buf; | ||
349 | |||
350 | buflen = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); | ||
351 | buf = malloc(buflen); | ||
352 | if (buf == NULL && buflen > 0) { | ||
353 | return gcry_error(GPG_ERR_ENOMEM); | ||
354 | } | ||
355 | gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, buf, buflen); | ||
356 | |||
357 | fprintf(privf, "%s", buf); | ||
358 | free(buf); | ||
359 | |||
360 | return gcry_error(GPG_ERR_NO_ERROR); | ||
361 | } | ||
362 | |||
363 | static gcry_error_t account_write(FILE *privf, const char *accountname, | ||
364 | const char *protocol, gcry_sexp_t privkey) | ||
365 | { | ||
366 | gcry_error_t err; | ||
367 | gcry_sexp_t names, protos; | ||
368 | |||
369 | fprintf(privf, " (account\n"); | ||
370 | |||
371 | err = gcry_sexp_build(&names, NULL, "(name %s)", accountname); | ||
372 | if (!err) { | ||
373 | err = sexp_write(privf, names); | ||
374 | gcry_sexp_release(names); | ||
375 | } | ||
376 | if (!err) err = gcry_sexp_build(&protos, NULL, "(protocol %s)", protocol); | ||
377 | if (!err) { | ||
378 | err = sexp_write(privf, protos); | ||
379 | gcry_sexp_release(protos); | ||
380 | } | ||
381 | if (!err) err = sexp_write(privf, privkey); | ||
382 | |||
383 | fprintf(privf, " )\n"); | ||
384 | |||
385 | return err; | ||
386 | } | ||
387 | |||
388 | /* Generate a private DSA key for a given account, storing it into a | ||
389 | * file on disk, and loading it into the given OtrlUserState. Overwrite any | ||
390 | * previously generated keys for that account in that OtrlUserState. */ | ||
391 | gcry_error_t otrl_privkey_generate(OtrlUserState us, const char *filename, | ||
392 | const char *accountname, const char *protocol) | ||
393 | { | ||
394 | gcry_error_t err; | ||
395 | FILE *privf; | ||
396 | #ifndef WIN32 | ||
397 | mode_t oldmask; | ||
398 | #endif | ||
399 | |||
400 | #ifndef WIN32 | ||
401 | oldmask = umask(077); | ||
402 | #endif | ||
403 | privf = fopen(filename, "w+b"); | ||
404 | if (!privf) { | ||
405 | #ifndef WIN32 | ||
406 | umask(oldmask); | ||
407 | #endif | ||
408 | err = gcry_error_from_errno(errno); | ||
409 | return err; | ||
410 | } | ||
411 | |||
412 | err = otrl_privkey_generate_FILEp(us, privf, accountname, protocol); | ||
413 | |||
414 | fclose(privf); | ||
415 | #ifndef WIN32 | ||
416 | umask(oldmask); | ||
417 | #endif | ||
418 | return err; | ||
419 | } | ||
420 | |||
421 | /* Generate a private DSA key for a given account, storing it into a | ||
422 | * FILE*, and loading it into the given OtrlUserState. Overwrite any | ||
423 | * previously generated keys for that account in that OtrlUserState. | ||
424 | * The FILE* must be open for reading and writing. */ | ||
425 | gcry_error_t otrl_privkey_generate_FILEp(OtrlUserState us, FILE *privf, | ||
426 | const char *accountname, const char *protocol) | ||
427 | { | ||
428 | gcry_error_t err; | ||
429 | gcry_sexp_t key, parms, privkey; | ||
430 | static const char *parmstr = "(genkey (dsa (nbits 4:1024)))"; | ||
431 | OtrlPrivKey *p; | ||
432 | |||
433 | if (!privf) return gcry_error(GPG_ERR_NO_ERROR); | ||
434 | |||
435 | /* Create a DSA key */ | ||
436 | err = gcry_sexp_new(&parms, parmstr, strlen(parmstr), 0); | ||
437 | if (err) { | ||
438 | return err; | ||
439 | } | ||
440 | err = gcry_pk_genkey(&key, parms); | ||
441 | gcry_sexp_release(parms); | ||
442 | if (err) { | ||
443 | return err; | ||
444 | } | ||
445 | |||
446 | /* Extract the privkey */ | ||
447 | privkey = gcry_sexp_find_token(key, "private-key", 0); | ||
448 | gcry_sexp_release(key); | ||
449 | |||
450 | /* Output the other keys we know */ | ||
451 | fprintf(privf, "(privkeys\n"); | ||
452 | |||
453 | for (p=us->privkey_root; p; p=p->next) { | ||
454 | /* Skip this one if our new key replaces it */ | ||
455 | if (!strcmp(p->accountname, accountname) && | ||
456 | !strcmp(p->protocol, protocol)) { | ||
457 | continue; | ||
458 | } | ||
459 | |||
460 | account_write(privf, p->accountname, p->protocol, p->privkey); | ||
461 | } | ||
462 | account_write(privf, accountname, protocol, privkey); | ||
463 | gcry_sexp_release(privkey); | ||
464 | fprintf(privf, ")\n"); | ||
465 | |||
466 | fseek(privf, 0, SEEK_SET); | ||
467 | |||
468 | return otrl_privkey_read_FILEp(us, privf); | ||
469 | } | ||
470 | |||
471 | /* Convert a hex character to a value */ | ||
472 | static unsigned int ctoh(char c) | ||
473 | { | ||
474 | if (c >= '0' && c <= '9') return c-'0'; | ||
475 | if (c >= 'a' && c <= 'f') return c-'a'+10; | ||
476 | if (c >= 'A' && c <= 'F') return c-'A'+10; | ||
477 | return 0; /* Unknown hex char */ | ||
478 | } | ||
479 | |||
480 | /* Read the fingerprint store from a file on disk into the given | ||
481 | * OtrlUserState. Use add_app_data to add application data to each | ||
482 | * ConnContext so created. */ | ||
483 | gcry_error_t otrl_privkey_read_fingerprints(OtrlUserState us, | ||
484 | const char *filename, | ||
485 | void (*add_app_data)(void *data, ConnContext *context), | ||
486 | void *data) | ||
487 | { | ||
488 | gcry_error_t err; | ||
489 | FILE *storef; | ||
490 | |||
491 | storef = fopen(filename, "rb"); | ||
492 | if (!storef) { | ||
493 | err = gcry_error_from_errno(errno); | ||
494 | return err; | ||
495 | } | ||
496 | |||
497 | err = otrl_privkey_read_fingerprints_FILEp(us, storef, add_app_data, data); | ||
498 | |||
499 | fclose(storef); | ||
500 | return err; | ||
501 | } | ||
502 | |||
503 | /* Read the fingerprint store from a FILE* into the given | ||
504 | * OtrlUserState. Use add_app_data to add application data to each | ||
505 | * ConnContext so created. The FILE* must be open for reading. */ | ||
506 | gcry_error_t otrl_privkey_read_fingerprints_FILEp(OtrlUserState us, | ||
507 | FILE *storef, | ||
508 | void (*add_app_data)(void *data, ConnContext *context), | ||
509 | void *data) | ||
510 | { | ||
511 | ConnContext *context; | ||
512 | char storeline[1000]; | ||
513 | unsigned char fingerprint[20]; | ||
514 | size_t maxsize = sizeof(storeline); | ||
515 | |||
516 | if (!storef) return gcry_error(GPG_ERR_NO_ERROR); | ||
517 | |||
518 | while(fgets(storeline, maxsize, storef)) { | ||
519 | char *username; | ||
520 | char *accountname; | ||
521 | char *protocol; | ||
522 | char *hex; | ||
523 | char *trust; | ||
524 | char *tab; | ||
525 | char *eol; | ||
526 | Fingerprint *fng; | ||
527 | int i, j; | ||
528 | /* Parse the line, which should be of the form: | ||
529 | * username\taccountname\tprotocol\t40_hex_nybbles\n */ | ||
530 | username = storeline; | ||
531 | tab = strchr(username, '\t'); | ||
532 | if (!tab) continue; | ||
533 | *tab = '\0'; | ||
534 | |||
535 | accountname = tab + 1; | ||
536 | tab = strchr(accountname, '\t'); | ||
537 | if (!tab) continue; | ||
538 | *tab = '\0'; | ||
539 | |||
540 | protocol = tab + 1; | ||
541 | tab = strchr(protocol, '\t'); | ||
542 | if (!tab) continue; | ||
543 | *tab = '\0'; | ||
544 | |||
545 | hex = tab + 1; | ||
546 | tab = strchr(hex, '\t'); | ||
547 | if (!tab) { | ||
548 | eol = strchr(hex, '\r'); | ||
549 | if (!eol) eol = strchr(hex, '\n'); | ||
550 | if (!eol) continue; | ||
551 | *eol = '\0'; | ||
552 | trust = NULL; | ||
553 | } else { | ||
554 | *tab = '\0'; | ||
555 | trust = tab + 1; | ||
556 | eol = strchr(trust, '\r'); | ||
557 | if (!eol) eol = strchr(trust, '\n'); | ||
558 | if (!eol) continue; | ||
559 | *eol = '\0'; | ||
560 | } | ||
561 | |||
562 | if (strlen(hex) != 40) continue; | ||
563 | for(j=0, i=0; i<40; i+=2) { | ||
564 | fingerprint[j++] = (ctoh(hex[i]) << 4) + (ctoh(hex[i+1])); | ||
565 | } | ||
566 | /* Get the context for this user, adding if not yet present */ | ||
567 | context = otrl_context_find(us, username, accountname, protocol, | ||
568 | 1, NULL, add_app_data, data); | ||
569 | /* Add the fingerprint if not already there */ | ||
570 | fng = otrl_context_find_fingerprint(context, fingerprint, 1, NULL); | ||
571 | otrl_context_set_trust(fng, trust); | ||
572 | } | ||
573 | |||
574 | return gcry_error(GPG_ERR_NO_ERROR); | ||
575 | } | ||
576 | |||
577 | /* Write the fingerprint store from a given OtrlUserState to a file on disk. */ | ||
578 | gcry_error_t otrl_privkey_write_fingerprints(OtrlUserState us, | ||
579 | const char *filename) | ||
580 | { | ||
581 | gcry_error_t err; | ||
582 | FILE *storef; | ||
583 | |||
584 | storef = fopen(filename, "wb"); | ||
585 | if (!storef) { | ||
586 | err = gcry_error_from_errno(errno); | ||
587 | return err; | ||
588 | } | ||
589 | |||
590 | err = otrl_privkey_write_fingerprints_FILEp(us, storef); | ||
591 | |||
592 | fclose(storef); | ||
593 | return err; | ||
594 | } | ||
595 | |||
596 | /* Write the fingerprint store from a given OtrlUserState to a FILE*. | ||
597 | * The FILE* must be open for writing. */ | ||
598 | gcry_error_t otrl_privkey_write_fingerprints_FILEp(OtrlUserState us, | ||
599 | FILE *storef) | ||
600 | { | ||
601 | ConnContext *context; | ||
602 | Fingerprint *fprint; | ||
603 | |||
604 | if (!storef) return gcry_error(GPG_ERR_NO_ERROR); | ||
605 | |||
606 | for(context = us->context_root; context; context = context->next) { | ||
607 | /* Don't both with the first (fingerprintless) entry. */ | ||
608 | for (fprint = context->fingerprint_root.next; fprint; | ||
609 | fprint = fprint->next) { | ||
610 | int i; | ||
611 | fprintf(storef, "%s\t%s\t%s\t", context->username, | ||
612 | context->accountname, context->protocol); | ||
613 | for(i=0;i<20;++i) { | ||
614 | fprintf(storef, "%02x", fprint->fingerprint[i]); | ||
615 | } | ||
616 | fprintf(storef, "\t%s\n", fprint->trust ? fprint->trust : ""); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | return gcry_error(GPG_ERR_NO_ERROR); | ||
621 | } | ||
622 | |||
623 | /* Fetch the private key from the given OtrlUserState associated with | ||
624 | * the given account */ | ||
625 | OtrlPrivKey *otrl_privkey_find(OtrlUserState us, const char *accountname, | ||
626 | const char *protocol) | ||
627 | { | ||
628 | OtrlPrivKey *p; | ||
629 | if (!accountname || !protocol) return NULL; | ||
630 | |||
631 | for(p=us->privkey_root; p; p=p->next) { | ||
632 | if (!strcmp(p->accountname, accountname) && | ||
633 | !strcmp(p->protocol, protocol)) { | ||
634 | return p; | ||
635 | } | ||
636 | } | ||
637 | return NULL; | ||
638 | } | ||
639 | |||
640 | /* Forget a private key */ | ||
641 | void otrl_privkey_forget(OtrlPrivKey *privkey) | ||
642 | { | ||
643 | free(privkey->accountname); | ||
644 | free(privkey->protocol); | ||
645 | gcry_sexp_release(privkey->privkey); | ||
646 | free(privkey->pubkey_data); | ||
647 | |||
648 | /* Re-link the list */ | ||
649 | *(privkey->tous) = privkey->next; | ||
650 | if (privkey->next) { | ||
651 | privkey->next->tous = privkey->tous; | ||
652 | } | ||
653 | |||
654 | /* Free the privkey struct */ | ||
655 | free(privkey); | ||
656 | } | ||
657 | |||
658 | /* Forget all private keys in a given OtrlUserState. */ | ||
659 | void otrl_privkey_forget_all(OtrlUserState us) | ||
660 | { | ||
661 | while (us->privkey_root) { | ||
662 | otrl_privkey_forget(us->privkey_root); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | /* Sign data using a private key. The data must be small enough to be | ||
667 | * signed (i.e. already hashed, if necessary). The signature will be | ||
668 | * returned in *sigp, which the caller must free(). Its length will be | ||
669 | * returned in *siglenp. */ | ||
670 | gcry_error_t otrl_privkey_sign(unsigned char **sigp, size_t *siglenp, | ||
671 | OtrlPrivKey *privkey, const unsigned char *data, size_t len) | ||
672 | { | ||
673 | gcry_mpi_t r,s, datampi; | ||
674 | gcry_sexp_t dsas, rs, ss, sigs, datas; | ||
675 | size_t nr, ns; | ||
676 | const enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
677 | |||
678 | if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA) | ||
679 | return gcry_error(GPG_ERR_INV_VALUE); | ||
680 | |||
681 | *sigp = malloc(40); | ||
682 | if (sigp == NULL) return gcry_error(GPG_ERR_ENOMEM); | ||
683 | *siglenp = 40; | ||
684 | |||
685 | if (len) { | ||
686 | gcry_mpi_scan(&datampi, GCRYMPI_FMT_USG, data, len, NULL); | ||
687 | } else { | ||
688 | datampi = gcry_mpi_set_ui(NULL, 0); | ||
689 | } | ||
690 | gcry_sexp_build(&datas, NULL, "(%m)", datampi); | ||
691 | gcry_mpi_release(datampi); | ||
692 | gcry_pk_sign(&sigs, datas, privkey->privkey); | ||
693 | gcry_sexp_release(datas); | ||
694 | dsas = gcry_sexp_find_token(sigs, "dsa", 0); | ||
695 | gcry_sexp_release(sigs); | ||
696 | rs = gcry_sexp_find_token(dsas, "r", 0); | ||
697 | ss = gcry_sexp_find_token(dsas, "s", 0); | ||
698 | gcry_sexp_release(dsas); | ||
699 | r = gcry_sexp_nth_mpi(rs, 1, GCRYMPI_FMT_USG); | ||
700 | gcry_sexp_release(rs); | ||
701 | s = gcry_sexp_nth_mpi(ss, 1, GCRYMPI_FMT_USG); | ||
702 | gcry_sexp_release(ss); | ||
703 | gcry_mpi_print(format, NULL, 0, &nr, r); | ||
704 | gcry_mpi_print(format, NULL, 0, &ns, s); | ||
705 | memset(*sigp, 0, 40); | ||
706 | gcry_mpi_print(format, (*sigp)+(20-nr), nr, NULL, r); | ||
707 | gcry_mpi_print(format, (*sigp)+20+(20-ns), ns, NULL, s); | ||
708 | gcry_mpi_release(r); | ||
709 | gcry_mpi_release(s); | ||
710 | |||
711 | return gcry_error(GPG_ERR_NO_ERROR); | ||
712 | } | ||
713 | |||
714 | /* Verify a signature on data using a public key. The data must be | ||
715 | * small enough to be signed (i.e. already hashed, if necessary). */ | ||
716 | gcry_error_t otrl_privkey_verify(const unsigned char *sigbuf, size_t siglen, | ||
717 | unsigned short pubkey_type, gcry_sexp_t pubs, | ||
718 | const unsigned char *data, size_t len) | ||
719 | { | ||
720 | gcry_error_t err; | ||
721 | gcry_mpi_t datampi,r,s; | ||
722 | gcry_sexp_t datas, sigs; | ||
723 | |||
724 | if (pubkey_type != OTRL_PUBKEY_TYPE_DSA || siglen != 40) | ||
725 | return gcry_error(GPG_ERR_INV_VALUE); | ||
726 | |||
727 | if (len) { | ||
728 | gcry_mpi_scan(&datampi, GCRYMPI_FMT_USG, data, len, NULL); | ||
729 | } else { | ||
730 | datampi = gcry_mpi_set_ui(NULL, 0); | ||
731 | } | ||
732 | gcry_sexp_build(&datas, NULL, "(%m)", datampi); | ||
733 | gcry_mpi_release(datampi); | ||
734 | gcry_mpi_scan(&r, GCRYMPI_FMT_USG, sigbuf, 20, NULL); | ||
735 | gcry_mpi_scan(&s, GCRYMPI_FMT_USG, sigbuf+20, 20, NULL); | ||
736 | gcry_sexp_build(&sigs, NULL, "(sig-val (dsa (r %m)(s %m)))", r, s); | ||
737 | gcry_mpi_release(r); | ||
738 | gcry_mpi_release(s); | ||
739 | |||
740 | err = gcry_pk_verify(sigs, datas, pubs); | ||
741 | gcry_sexp_release(datas); | ||
742 | gcry_sexp_release(sigs); | ||
743 | |||
744 | return err; | ||
745 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/privkey.h b/linden/indra/libotr/libotr-3.2.0/src/privkey.h new file mode 100755 index 0000000..83e7d48 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/privkey.h | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __PRIVKEY_H__ | ||
21 | #define __PRIVKEY_H__ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include "privkey-t.h" | ||
25 | #include "userstate.h" | ||
26 | |||
27 | /* Convert a 20-byte hash value to a 45-byte human-readable value */ | ||
28 | void otrl_privkey_hash_to_human(char human[45], const unsigned char hash[20]); | ||
29 | |||
30 | /* Calculate a human-readable hash of our DSA public key. Return it in | ||
31 | * the passed fingerprint buffer. Return NULL on error, or a pointer to | ||
32 | * the given buffer on success. */ | ||
33 | char *otrl_privkey_fingerprint(OtrlUserState us, char fingerprint[45], | ||
34 | const char *accountname, const char *protocol); | ||
35 | |||
36 | /* Calculate a raw hash of our DSA public key. Return it in the passed | ||
37 | * fingerprint buffer. Return NULL on error, or a pointer to the given | ||
38 | * buffer on success. */ | ||
39 | unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us, | ||
40 | unsigned char hash[20], const char *accountname, const char *protocol); | ||
41 | |||
42 | /* Read a sets of private DSA keys from a file on disk into the given | ||
43 | * OtrlUserState. */ | ||
44 | gcry_error_t otrl_privkey_read(OtrlUserState us, const char *filename); | ||
45 | |||
46 | /* Read a sets of private DSA keys from a FILE* into the given | ||
47 | * OtrlUserState. The FILE* must be open for reading. */ | ||
48 | gcry_error_t otrl_privkey_read_FILEp(OtrlUserState us, FILE *privf); | ||
49 | |||
50 | /* Generate a private DSA key for a given account, storing it into a | ||
51 | * file on disk, and loading it into the given OtrlUserState. Overwrite any | ||
52 | * previously generated keys for that account in that OtrlUserState. */ | ||
53 | gcry_error_t otrl_privkey_generate(OtrlUserState us, const char *filename, | ||
54 | const char *accountname, const char *protocol); | ||
55 | |||
56 | /* Generate a private DSA key for a given account, storing it into a | ||
57 | * FILE*, and loading it into the given OtrlUserState. Overwrite any | ||
58 | * previously generated keys for that account in that OtrlUserState. | ||
59 | * The FILE* must be open for reading and writing. */ | ||
60 | gcry_error_t otrl_privkey_generate_FILEp(OtrlUserState us, FILE *privf, | ||
61 | const char *accountname, const char *protocol); | ||
62 | |||
63 | /* Read the fingerprint store from a file on disk into the given | ||
64 | * OtrlUserState. Use add_app_data to add application data to each | ||
65 | * ConnContext so created. */ | ||
66 | gcry_error_t otrl_privkey_read_fingerprints(OtrlUserState us, | ||
67 | const char *filename, | ||
68 | void (*add_app_data)(void *data, ConnContext *context), | ||
69 | void *data); | ||
70 | |||
71 | /* Read the fingerprint store from a FILE* into the given | ||
72 | * OtrlUserState. Use add_app_data to add application data to each | ||
73 | * ConnContext so created. The FILE* must be open for reading. */ | ||
74 | gcry_error_t otrl_privkey_read_fingerprints_FILEp(OtrlUserState us, | ||
75 | FILE *storef, | ||
76 | void (*add_app_data)(void *data, ConnContext *context), | ||
77 | void *data); | ||
78 | |||
79 | /* Write the fingerprint store from a given OtrlUserState to a file on disk. */ | ||
80 | gcry_error_t otrl_privkey_write_fingerprints(OtrlUserState us, | ||
81 | const char *filename); | ||
82 | |||
83 | /* Write the fingerprint store from a given OtrlUserState to a FILE*. | ||
84 | * The FILE* must be open for writing. */ | ||
85 | gcry_error_t otrl_privkey_write_fingerprints_FILEp(OtrlUserState us, | ||
86 | FILE *storef); | ||
87 | |||
88 | /* Fetch the private key from the given OtrlUserState associated with | ||
89 | * the given account */ | ||
90 | OtrlPrivKey *otrl_privkey_find(OtrlUserState us, const char *accountname, | ||
91 | const char *protocol); | ||
92 | |||
93 | /* Forget a private key */ | ||
94 | void otrl_privkey_forget(OtrlPrivKey *privkey); | ||
95 | |||
96 | /* Forget all private keys in a given OtrlUserState. */ | ||
97 | void otrl_privkey_forget_all(OtrlUserState us); | ||
98 | |||
99 | /* Sign data using a private key. The data must be small enough to be | ||
100 | * signed (i.e. already hashed, if necessary). The signature will be | ||
101 | * returned in *sigp, which the caller must free(). Its length will be | ||
102 | * returned in *siglenp. */ | ||
103 | gcry_error_t otrl_privkey_sign(unsigned char **sigp, size_t *siglenp, | ||
104 | OtrlPrivKey *privkey, const unsigned char *data, size_t len); | ||
105 | |||
106 | /* Verify a signature on data using a public key. The data must be | ||
107 | * small enough to be signed (i.e. already hashed, if necessary). */ | ||
108 | gcry_error_t otrl_privkey_verify(const unsigned char *sigbuf, size_t siglen, | ||
109 | unsigned short pubkey_type, gcry_sexp_t pubs, | ||
110 | const unsigned char *data, size_t len); | ||
111 | |||
112 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/proto.c b/linden/indra/libotr/libotr-3.2.0/src/proto.c new file mode 100755 index 0000000..2044e06 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/proto.c | |||
@@ -0,0 +1,998 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* OTR Protocol implementation. This file should be independent of | ||
21 | * gaim, so that it can be used to make other clients. */ | ||
22 | |||
23 | /* system headers */ | ||
24 | #include <stdio.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <assert.h> | ||
27 | |||
28 | /* libgcrypt headers */ | ||
29 | #include <gcrypt.h> | ||
30 | |||
31 | /* libotr headers */ | ||
32 | #include "b64.h" | ||
33 | #include "privkey.h" | ||
34 | #include "proto.h" | ||
35 | #include "mem.h" | ||
36 | #include "version.h" | ||
37 | #include "tlv.h" | ||
38 | #include "serial.h" | ||
39 | |||
40 | /* For now, we need to know the API version the client is using so that | ||
41 | * we don't use any UI callbacks it hasn't set. */ | ||
42 | unsigned int otrl_api_version = 0; | ||
43 | |||
44 | /* Initialize the OTR library. Pass the version of the API you are | ||
45 | * using. */ | ||
46 | void otrl_init(unsigned int ver_major, unsigned int ver_minor, | ||
47 | unsigned int ver_sub) | ||
48 | { | ||
49 | unsigned int api_version; | ||
50 | |||
51 | /* The major versions have to match, and you can't be using a newer | ||
52 | * minor version than we expect. */ | ||
53 | if (ver_major != OTRL_VERSION_MAJOR || ver_minor > OTRL_VERSION_MINOR) { | ||
54 | fprintf(stderr, "Expected libotr API version %u.%u.%u incompatible " | ||
55 | "with actual version %u.%u.%u. Aborting.\n", | ||
56 | ver_major, ver_minor, ver_sub, | ||
57 | OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, OTRL_VERSION_SUB); | ||
58 | exit(1); | ||
59 | } | ||
60 | |||
61 | /* Set the API version. If we get called multiple times for some | ||
62 | * reason, take the smallest value. */ | ||
63 | api_version = (ver_major << 16) | (ver_minor << 8) | (ver_sub); | ||
64 | if (otrl_api_version == 0 || otrl_api_version > api_version) { | ||
65 | otrl_api_version = api_version; | ||
66 | } | ||
67 | |||
68 | /* Initialize the memory module */ | ||
69 | otrl_mem_init(); | ||
70 | |||
71 | /* Initialize the DH module */ | ||
72 | otrl_dh_init(); | ||
73 | |||
74 | /* Initialize the SM module */ | ||
75 | otrl_sm_init(); | ||
76 | } | ||
77 | |||
78 | /* Return a pointer to a static string containing the version number of | ||
79 | * the OTR library. */ | ||
80 | const char *otrl_version(void) | ||
81 | { | ||
82 | return OTRL_VERSION; | ||
83 | } | ||
84 | |||
85 | /* Store some MAC keys to be revealed later */ | ||
86 | static gcry_error_t reveal_macs(ConnContext *context, | ||
87 | DH_sesskeys *sess1, DH_sesskeys *sess2) | ||
88 | { | ||
89 | unsigned int numnew = sess1->rcvmacused + sess1->sendmacused + | ||
90 | sess2->rcvmacused + sess2->sendmacused; | ||
91 | unsigned int newnumsaved; | ||
92 | unsigned char *newmacs; | ||
93 | |||
94 | /* Is there anything to do? */ | ||
95 | if (numnew == 0) return gcry_error(GPG_ERR_NO_ERROR); | ||
96 | |||
97 | newnumsaved = context->numsavedkeys + numnew; | ||
98 | newmacs = realloc(context->saved_mac_keys, | ||
99 | newnumsaved * 20); | ||
100 | if (!newmacs) { | ||
101 | return gcry_error(GPG_ERR_ENOMEM); | ||
102 | } | ||
103 | if (sess1->rcvmacused) { | ||
104 | memmove(newmacs + context->numsavedkeys * 20, sess1->rcvmackey, 20); | ||
105 | context->numsavedkeys++; | ||
106 | } | ||
107 | if (sess1->sendmacused) { | ||
108 | memmove(newmacs + context->numsavedkeys * 20, sess1->sendmackey, 20); | ||
109 | context->numsavedkeys++; | ||
110 | } | ||
111 | if (sess2->rcvmacused) { | ||
112 | memmove(newmacs + context->numsavedkeys * 20, sess2->rcvmackey, 20); | ||
113 | context->numsavedkeys++; | ||
114 | } | ||
115 | if (sess2->sendmacused) { | ||
116 | memmove(newmacs + context->numsavedkeys * 20, sess2->sendmackey, 20); | ||
117 | context->numsavedkeys++; | ||
118 | } | ||
119 | context->saved_mac_keys = newmacs; | ||
120 | |||
121 | return gcry_error(GPG_ERR_NO_ERROR); | ||
122 | } | ||
123 | |||
124 | /* Make a new DH key for us, and rotate old old ones. Be sure to keep | ||
125 | * the sesskeys array in sync. */ | ||
126 | static gcry_error_t rotate_dh_keys(ConnContext *context) | ||
127 | { | ||
128 | gcry_error_t err; | ||
129 | |||
130 | /* Rotate the keypair */ | ||
131 | otrl_dh_keypair_free(&(context->our_old_dh_key)); | ||
132 | memmove(&(context->our_old_dh_key), &(context->our_dh_key), | ||
133 | sizeof(DH_keypair)); | ||
134 | |||
135 | /* Rotate the session keys */ | ||
136 | err = reveal_macs(context, &(context->sesskeys[1][0]), | ||
137 | &(context->sesskeys[1][1])); | ||
138 | if (err) return err; | ||
139 | otrl_dh_session_free(&(context->sesskeys[1][0])); | ||
140 | otrl_dh_session_free(&(context->sesskeys[1][1])); | ||
141 | memmove(&(context->sesskeys[1][0]), &(context->sesskeys[0][0]), | ||
142 | sizeof(DH_sesskeys)); | ||
143 | memmove(&(context->sesskeys[1][1]), &(context->sesskeys[0][1]), | ||
144 | sizeof(DH_sesskeys)); | ||
145 | |||
146 | /* Create a new DH key */ | ||
147 | otrl_dh_gen_keypair(DH1536_GROUP_ID, &(context->our_dh_key)); | ||
148 | context->our_keyid++; | ||
149 | |||
150 | /* Make the session keys */ | ||
151 | if (context->their_y) { | ||
152 | err = otrl_dh_session(&(context->sesskeys[0][0]), | ||
153 | &(context->our_dh_key), context->their_y); | ||
154 | if (err) return err; | ||
155 | } else { | ||
156 | otrl_dh_session_blank(&(context->sesskeys[0][0])); | ||
157 | } | ||
158 | if (context->their_old_y) { | ||
159 | err = otrl_dh_session(&(context->sesskeys[0][1]), | ||
160 | &(context->our_dh_key), context->their_old_y); | ||
161 | if (err) return err; | ||
162 | } else { | ||
163 | otrl_dh_session_blank(&(context->sesskeys[0][1])); | ||
164 | } | ||
165 | return gcry_error(GPG_ERR_NO_ERROR); | ||
166 | } | ||
167 | |||
168 | /* Rotate in a new DH public key for our correspondent. Be sure to keep | ||
169 | * the sesskeys array in sync. */ | ||
170 | static gcry_error_t rotate_y_keys(ConnContext *context, gcry_mpi_t new_y) | ||
171 | { | ||
172 | gcry_error_t err; | ||
173 | |||
174 | /* Rotate the public key */ | ||
175 | gcry_mpi_release(context->their_old_y); | ||
176 | context->their_old_y = context->their_y; | ||
177 | |||
178 | /* Rotate the session keys */ | ||
179 | err = reveal_macs(context, &(context->sesskeys[0][1]), | ||
180 | &(context->sesskeys[1][1])); | ||
181 | if (err) return err; | ||
182 | otrl_dh_session_free(&(context->sesskeys[0][1])); | ||
183 | otrl_dh_session_free(&(context->sesskeys[1][1])); | ||
184 | memmove(&(context->sesskeys[0][1]), &(context->sesskeys[0][0]), | ||
185 | sizeof(DH_sesskeys)); | ||
186 | memmove(&(context->sesskeys[1][1]), &(context->sesskeys[1][0]), | ||
187 | sizeof(DH_sesskeys)); | ||
188 | |||
189 | /* Copy in the new public key */ | ||
190 | context->their_y = gcry_mpi_copy(new_y); | ||
191 | context->their_keyid++; | ||
192 | |||
193 | /* Make the session keys */ | ||
194 | err = otrl_dh_session(&(context->sesskeys[0][0]), | ||
195 | &(context->our_dh_key), context->their_y); | ||
196 | if (err) return err; | ||
197 | err = otrl_dh_session(&(context->sesskeys[1][0]), | ||
198 | &(context->our_old_dh_key), context->their_y); | ||
199 | if (err) return err; | ||
200 | |||
201 | return gcry_error(GPG_ERR_NO_ERROR); | ||
202 | } | ||
203 | |||
204 | /* Return a pointer to a newly-allocated OTR query message, customized | ||
205 | * with our name. The caller should free() the result when he's done | ||
206 | * with it. */ | ||
207 | char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy) | ||
208 | { | ||
209 | char *msg; | ||
210 | int v1_supported, v2_supported; | ||
211 | const char *version_tag; | ||
212 | /* Don't use g_strdup_printf here, because someone (not us) is going | ||
213 | * to free() the *message pointer, not g_free() it. We can't | ||
214 | * require that they g_free() it, because this pointer will probably | ||
215 | * get passed to the main IM application for processing (and | ||
216 | * free()ing). */ | ||
217 | const char *format = "?OTR%s\n%s has requested an Off-the-Record " | ||
218 | "private conversation. However, your viewer doesn't support " | ||
219 | "OTR. Emerald Viewer does, see " | ||
220 | "http://modularsystems.sl/ for more information about GreenLife, " | ||
221 | "and http://otr.cypherpunks.ca/ for more information about OTR."; | ||
222 | |||
223 | /* Figure out the version tag */ | ||
224 | v1_supported = (policy & OTRL_POLICY_ALLOW_V1); | ||
225 | v2_supported = (policy & OTRL_POLICY_ALLOW_V2); | ||
226 | if (v1_supported) { | ||
227 | if (v2_supported) { | ||
228 | version_tag = "?v2?"; | ||
229 | } else { | ||
230 | version_tag = "?"; | ||
231 | } | ||
232 | } else { | ||
233 | if (v2_supported) { | ||
234 | version_tag = "v2?"; | ||
235 | } else { | ||
236 | version_tag = "v?"; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /* Remove two "%s", add '\0' */ | ||
241 | msg = malloc(strlen(format) + strlen(version_tag) + strlen(ourname) - 3); | ||
242 | if (!msg) return NULL; | ||
243 | sprintf(msg, format, version_tag, ourname); | ||
244 | return msg; | ||
245 | } | ||
246 | |||
247 | /* Return the best version of OTR support by both sides, given an OTR | ||
248 | * Query Message and the local policy. */ | ||
249 | unsigned int otrl_proto_query_bestversion(const char *querymsg, | ||
250 | OtrlPolicy policy) | ||
251 | { | ||
252 | char *otrtag; | ||
253 | unsigned int query_versions = 0; | ||
254 | |||
255 | otrtag = strstr(querymsg, "?OTR"); | ||
256 | otrtag += 4; | ||
257 | if (*otrtag == '?') { | ||
258 | query_versions = (1<<0); | ||
259 | ++otrtag; | ||
260 | } | ||
261 | if (*otrtag == 'v') { | ||
262 | for(++otrtag; *otrtag && *otrtag != '?'; ++otrtag) { | ||
263 | switch(*otrtag) { | ||
264 | case '2': | ||
265 | query_versions |= (1<<1); | ||
266 | break; | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) { | ||
272 | return 2; | ||
273 | } | ||
274 | if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) { | ||
275 | return 1; | ||
276 | } | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | /* Locate any whitespace tag in this message, and return the best | ||
281 | * version of OTR support on both sides. Set *starttagp and *endtagp to | ||
282 | * the start and end of the located tag, so that it can be snipped out. */ | ||
283 | unsigned int otrl_proto_whitespace_bestversion(const char *msg, | ||
284 | const char **starttagp, const char **endtagp, OtrlPolicy policy) | ||
285 | { | ||
286 | const char *starttag, *endtag; | ||
287 | unsigned int query_versions = 0; | ||
288 | |||
289 | *starttagp = NULL; | ||
290 | *endtagp = NULL; | ||
291 | |||
292 | starttag = strstr(msg, OTRL_MESSAGE_TAG_BASE); | ||
293 | if (!starttag) return 0; | ||
294 | |||
295 | endtag = starttag + strlen(OTRL_MESSAGE_TAG_BASE); | ||
296 | |||
297 | /* Look for groups of 8 spaces and/or tabs */ | ||
298 | while(1) { | ||
299 | int i; | ||
300 | int allwhite = 1; | ||
301 | for(i=0;i<8;++i) { | ||
302 | if (endtag[i] != ' ' && endtag[i] != '\t') { | ||
303 | allwhite = 0; | ||
304 | break; | ||
305 | } | ||
306 | } | ||
307 | if (allwhite) { | ||
308 | if (!strncmp(endtag, OTRL_MESSAGE_TAG_V1, 8)) { | ||
309 | query_versions |= (1<<0); | ||
310 | } | ||
311 | if (!strncmp(endtag, OTRL_MESSAGE_TAG_V2, 8)) { | ||
312 | query_versions |= (1<<1); | ||
313 | } | ||
314 | endtag += 8; | ||
315 | } else { | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | *starttagp = starttag; | ||
321 | *endtagp = endtag; | ||
322 | |||
323 | if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) { | ||
324 | return 2; | ||
325 | } | ||
326 | if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) { | ||
327 | return 1; | ||
328 | } | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* Return the Message type of the given message. */ | ||
333 | OtrlMessageType otrl_proto_message_type(const char *message) | ||
334 | { | ||
335 | char *otrtag; | ||
336 | |||
337 | otrtag = strstr(message, "?OTR"); | ||
338 | |||
339 | if (!otrtag) { | ||
340 | if (strstr(message, OTRL_MESSAGE_TAG_BASE)) { | ||
341 | return OTRL_MSGTYPE_TAGGEDPLAINTEXT; | ||
342 | } else { | ||
343 | return OTRL_MSGTYPE_NOTOTR; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if (!strncmp(otrtag, "?OTR?", 5)) return OTRL_MSGTYPE_QUERY; | ||
348 | if (!strncmp(otrtag, "?OTRv", 5)) return OTRL_MSGTYPE_QUERY; | ||
349 | if (!strncmp(otrtag, "?OTR:AAIC", 9)) return OTRL_MSGTYPE_DH_COMMIT; | ||
350 | if (!strncmp(otrtag, "?OTR:AAIK", 9)) return OTRL_MSGTYPE_DH_KEY; | ||
351 | if (!strncmp(otrtag, "?OTR:AAIR", 9)) return OTRL_MSGTYPE_REVEALSIG; | ||
352 | if (!strncmp(otrtag, "?OTR:AAIS", 9)) return OTRL_MSGTYPE_SIGNATURE; | ||
353 | if (!strncmp(otrtag, "?OTR:AAEK", 9)) return OTRL_MSGTYPE_V1_KEYEXCH; | ||
354 | if (!strncmp(otrtag, "?OTR:AAED", 9)) return OTRL_MSGTYPE_DATA; | ||
355 | if (!strncmp(otrtag, "?OTR:AAID", 9)) return OTRL_MSGTYPE_DATA; | ||
356 | if (!strncmp(otrtag, "?OTR Error:", 11)) return OTRL_MSGTYPE_ERROR; | ||
357 | |||
358 | return OTRL_MSGTYPE_UNKNOWN; | ||
359 | } | ||
360 | |||
361 | /* Create an OTR Data message. Pass the plaintext as msg, and an | ||
362 | * optional chain of TLVs. A newly-allocated string will be returned in | ||
363 | * *encmessagep. */ | ||
364 | gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context, | ||
365 | const char *msg, const OtrlTLV *tlvs, unsigned char flags) | ||
366 | { | ||
367 | size_t justmsglen = strlen(msg); | ||
368 | size_t msglen = justmsglen + 1 + otrl_tlv_seriallen(tlvs); | ||
369 | size_t buflen; | ||
370 | size_t pubkeylen; | ||
371 | unsigned char *buf = NULL; | ||
372 | unsigned char *bufp; | ||
373 | size_t lenp; | ||
374 | DH_sesskeys *sess = &(context->sesskeys[1][0]); | ||
375 | gcry_error_t err; | ||
376 | size_t reveallen = 20 * context->numsavedkeys; | ||
377 | size_t base64len; | ||
378 | char *base64buf = NULL; | ||
379 | unsigned char *msgbuf = NULL; | ||
380 | enum gcry_mpi_format format = GCRYMPI_FMT_USG; | ||
381 | char *msgdup; | ||
382 | int version = context->protocol_version; | ||
383 | |||
384 | /* Make sure we're actually supposed to be able to encrypt */ | ||
385 | if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED || | ||
386 | context->their_keyid == 0) { | ||
387 | return gcry_error(GPG_ERR_CONFLICT); | ||
388 | } | ||
389 | |||
390 | /* We need to copy the incoming msg, since it might be an alias for | ||
391 | * context->lastmessage, which we'll be freeing soon. */ | ||
392 | msgdup = gcry_malloc_secure(justmsglen + 1); | ||
393 | if (msgdup == NULL) { | ||
394 | return gcry_error(GPG_ERR_ENOMEM); | ||
395 | } | ||
396 | strcpy(msgdup, msg); | ||
397 | |||
398 | *encmessagep = NULL; | ||
399 | |||
400 | /* Header, send keyid, recv keyid, counter, msg len, msg | ||
401 | * len of revealed mac keys, revealed mac keys, MAC */ | ||
402 | buflen = 3 + (version == 2 ? 1 : 0) + 4 + 4 + 8 + 4 + msglen + | ||
403 | 4 + reveallen + 20; | ||
404 | gcry_mpi_print(format, NULL, 0, &pubkeylen, context->our_dh_key.pub); | ||
405 | buflen += pubkeylen + 4; | ||
406 | buf = malloc(buflen); | ||
407 | msgbuf = gcry_malloc_secure(msglen); | ||
408 | if (buf == NULL || msgbuf == NULL) { | ||
409 | free(buf); | ||
410 | gcry_free(msgbuf); | ||
411 | gcry_free(msgdup); | ||
412 | return gcry_error(GPG_ERR_ENOMEM); | ||
413 | } | ||
414 | memmove(msgbuf, msgdup, justmsglen); | ||
415 | msgbuf[justmsglen] = '\0'; | ||
416 | otrl_tlv_serialize(msgbuf + justmsglen + 1, tlvs); | ||
417 | bufp = buf; | ||
418 | lenp = buflen; | ||
419 | if (version == 1) { | ||
420 | memmove(bufp, "\x00\x01\x03", 3); /* header */ | ||
421 | } else { | ||
422 | memmove(bufp, "\x00\x02\x03", 3); /* header */ | ||
423 | } | ||
424 | debug_data("Header", bufp, 3); | ||
425 | bufp += 3; lenp -= 3; | ||
426 | if (version == 2) { | ||
427 | bufp[0] = flags; | ||
428 | bufp += 1; lenp -= 1; | ||
429 | } | ||
430 | write_int(context->our_keyid-1); /* sender keyid */ | ||
431 | debug_int("Sender keyid", bufp-4); | ||
432 | write_int(context->their_keyid); /* recipient keyid */ | ||
433 | debug_int("Recipient keyid", bufp-4); | ||
434 | |||
435 | write_mpi(context->our_dh_key.pub, pubkeylen, "Y"); /* Y */ | ||
436 | |||
437 | otrl_dh_incctr(sess->sendctr); | ||
438 | memmove(bufp, sess->sendctr, 8); /* Counter (top 8 bytes only) */ | ||
439 | debug_data("Counter", bufp, 8); | ||
440 | bufp += 8; lenp -= 8; | ||
441 | |||
442 | write_int(msglen); /* length of encrypted data */ | ||
443 | debug_int("Msg len", bufp-4); | ||
444 | |||
445 | err = gcry_cipher_reset(sess->sendenc); | ||
446 | if (err) goto err; | ||
447 | err = gcry_cipher_setctr(sess->sendenc, sess->sendctr, 16); | ||
448 | if (err) goto err; | ||
449 | err = gcry_cipher_encrypt(sess->sendenc, bufp, msglen, msgbuf, msglen); | ||
450 | if (err) goto err; /* encrypted data */ | ||
451 | debug_data("Enc data", bufp, msglen); | ||
452 | bufp += msglen; | ||
453 | lenp -= msglen; | ||
454 | |||
455 | gcry_md_reset(sess->sendmac); | ||
456 | gcry_md_write(sess->sendmac, buf, bufp-buf); | ||
457 | memmove(bufp, gcry_md_read(sess->sendmac, GCRY_MD_SHA1), 20); | ||
458 | debug_data("MAC", bufp, 20); | ||
459 | bufp += 20; /* MAC */ | ||
460 | lenp -= 20; | ||
461 | |||
462 | write_int(reveallen); /* length of revealed MAC keys */ | ||
463 | debug_int("Revealed MAC length", bufp-4); | ||
464 | |||
465 | if (reveallen > 0) { | ||
466 | memmove(bufp, context->saved_mac_keys, reveallen); | ||
467 | debug_data("Revealed MAC data", bufp, reveallen); | ||
468 | bufp += reveallen; lenp -= reveallen; | ||
469 | free(context->saved_mac_keys); | ||
470 | context->saved_mac_keys = NULL; | ||
471 | context->numsavedkeys = 0; | ||
472 | } | ||
473 | |||
474 | assert(lenp == 0); | ||
475 | |||
476 | /* Make the base64-encoding. */ | ||
477 | base64len = ((buflen + 2) / 3) * 4; | ||
478 | base64buf = malloc(5 + base64len + 1 + 1); | ||
479 | if (base64buf == NULL) { | ||
480 | err = gcry_error(GPG_ERR_ENOMEM); | ||
481 | goto err; | ||
482 | } | ||
483 | memmove(base64buf, "?OTR:", 5); | ||
484 | otrl_base64_encode(base64buf+5, buf, buflen); | ||
485 | base64buf[5 + base64len] = '.'; | ||
486 | base64buf[5 + base64len + 1] = '\0'; | ||
487 | |||
488 | free(buf); | ||
489 | gcry_free(msgbuf); | ||
490 | *encmessagep = base64buf; | ||
491 | gcry_free(context->lastmessage); | ||
492 | context->lastmessage = NULL; | ||
493 | context->may_retransmit = 0; | ||
494 | if (msglen > 0) { | ||
495 | const char *prefix = "[resent] "; | ||
496 | size_t prefixlen = strlen(prefix); | ||
497 | if (!strncmp(prefix, msgdup, prefixlen)) { | ||
498 | /* The prefix is already there. Don't add it again. */ | ||
499 | prefix = ""; | ||
500 | prefixlen = 0; | ||
501 | } | ||
502 | context->lastmessage = gcry_malloc_secure(prefixlen + justmsglen + 1); | ||
503 | if (context->lastmessage) { | ||
504 | strcpy(context->lastmessage, prefix); | ||
505 | strcat(context->lastmessage, msgdup); | ||
506 | } | ||
507 | } | ||
508 | gcry_free(msgdup); | ||
509 | return gcry_error(GPG_ERR_NO_ERROR); | ||
510 | err: | ||
511 | free(buf); | ||
512 | gcry_free(msgbuf); | ||
513 | gcry_free(msgdup); | ||
514 | *encmessagep = NULL; | ||
515 | return err; | ||
516 | } | ||
517 | |||
518 | /* Extract the flags from an otherwise unreadable Data Message. */ | ||
519 | gcry_error_t otrl_proto_data_read_flags(const char *datamsg, | ||
520 | unsigned char *flagsp) | ||
521 | { | ||
522 | char *otrtag, *endtag; | ||
523 | unsigned char *rawmsg = NULL; | ||
524 | unsigned char *bufp; | ||
525 | size_t msglen, rawlen, lenp; | ||
526 | unsigned char version; | ||
527 | |||
528 | if (flagsp) *flagsp = 0; | ||
529 | otrtag = strstr(datamsg, "?OTR:"); | ||
530 | if (!otrtag) { | ||
531 | goto invval; | ||
532 | } | ||
533 | endtag = strchr(otrtag, '.'); | ||
534 | if (endtag) { | ||
535 | msglen = endtag-otrtag; | ||
536 | } else { | ||
537 | msglen = strlen(otrtag); | ||
538 | } | ||
539 | |||
540 | /* Base64-decode the message */ | ||
541 | rawlen = ((msglen-5) / 4) * 3; /* maximum possible */ | ||
542 | rawmsg = malloc(rawlen); | ||
543 | if (!rawmsg && rawlen > 0) { | ||
544 | return gcry_error(GPG_ERR_ENOMEM); | ||
545 | } | ||
546 | rawlen = otrl_base64_decode(rawmsg, otrtag+5, msglen-5); /* actual size */ | ||
547 | |||
548 | bufp = rawmsg; | ||
549 | lenp = rawlen; | ||
550 | |||
551 | require_len(3); | ||
552 | if (memcmp(bufp, "\x00\x01\x03", 3) && memcmp(bufp, "\x00\x02\x03", 3)) { | ||
553 | /* Invalid header */ | ||
554 | goto invval; | ||
555 | } | ||
556 | version = bufp[1]; | ||
557 | bufp += 3; lenp -= 3; | ||
558 | |||
559 | if (version == 2) { | ||
560 | require_len(1); | ||
561 | if (flagsp) *flagsp = bufp[0]; | ||
562 | bufp += 1; lenp -= 1; | ||
563 | } | ||
564 | |||
565 | free(rawmsg); | ||
566 | return gcry_error(GPG_ERR_NO_ERROR); | ||
567 | |||
568 | invval: | ||
569 | free(rawmsg); | ||
570 | return gcry_error(GPG_ERR_INV_VALUE); | ||
571 | } | ||
572 | |||
573 | /* Accept an OTR Data Message in datamsg. Decrypt it and put the | ||
574 | * plaintext into *plaintextp, and any TLVs into tlvsp. Put any | ||
575 | * received flags into *flagsp (if non-NULL). */ | ||
576 | gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp, | ||
577 | ConnContext *context, const char *datamsg, unsigned char *flagsp) | ||
578 | { | ||
579 | char *otrtag, *endtag; | ||
580 | gcry_error_t err; | ||
581 | unsigned char *rawmsg = NULL; | ||
582 | size_t msglen, rawlen, lenp; | ||
583 | unsigned char *macstart, *macend; | ||
584 | unsigned char *bufp; | ||
585 | unsigned int sender_keyid, recipient_keyid; | ||
586 | gcry_mpi_t sender_next_y = NULL; | ||
587 | unsigned char ctr[8]; | ||
588 | unsigned int datalen, reveallen; | ||
589 | unsigned char *data = NULL; | ||
590 | unsigned char *nul = NULL; | ||
591 | unsigned char givenmac[20]; | ||
592 | DH_sesskeys *sess; | ||
593 | unsigned char version; | ||
594 | |||
595 | *plaintextp = NULL; | ||
596 | *tlvsp = NULL; | ||
597 | if (flagsp) *flagsp = 0; | ||
598 | otrtag = strstr(datamsg, "?OTR:"); | ||
599 | if (!otrtag) { | ||
600 | goto invval; | ||
601 | } | ||
602 | endtag = strchr(otrtag, '.'); | ||
603 | if (endtag) { | ||
604 | msglen = endtag-otrtag; | ||
605 | } else { | ||
606 | msglen = strlen(otrtag); | ||
607 | } | ||
608 | |||
609 | /* Base64-decode the message */ | ||
610 | rawlen = ((msglen-5) / 4) * 3; /* maximum possible */ | ||
611 | rawmsg = malloc(rawlen); | ||
612 | if (!rawmsg && rawlen > 0) { | ||
613 | err = gcry_error(GPG_ERR_ENOMEM); | ||
614 | goto err; | ||
615 | } | ||
616 | rawlen = otrl_base64_decode(rawmsg, otrtag+5, msglen-5); /* actual size */ | ||
617 | |||
618 | bufp = rawmsg; | ||
619 | lenp = rawlen; | ||
620 | |||
621 | macstart = bufp; | ||
622 | require_len(3); | ||
623 | if (memcmp(bufp, "\x00\x01\x03", 3) && memcmp(bufp, "\x00\x02\x03", 3)) { | ||
624 | /* Invalid header */ | ||
625 | goto invval; | ||
626 | } | ||
627 | version = bufp[1]; | ||
628 | bufp += 3; lenp -= 3; | ||
629 | |||
630 | if (version == 2) { | ||
631 | require_len(1); | ||
632 | if (flagsp) *flagsp = bufp[0]; | ||
633 | bufp += 1; lenp -= 1; | ||
634 | } | ||
635 | read_int(sender_keyid); | ||
636 | read_int(recipient_keyid); | ||
637 | read_mpi(sender_next_y); | ||
638 | require_len(8); | ||
639 | memmove(ctr, bufp, 8); | ||
640 | bufp += 8; lenp -= 8; | ||
641 | read_int(datalen); | ||
642 | require_len(datalen); | ||
643 | data = malloc(datalen+1); | ||
644 | if (!data) { | ||
645 | err = gcry_error(GPG_ERR_ENOMEM); | ||
646 | goto err; | ||
647 | } | ||
648 | memmove(data, bufp, datalen); | ||
649 | data[datalen] = '\0'; | ||
650 | bufp += datalen; lenp -= datalen; | ||
651 | macend = bufp; | ||
652 | require_len(20); | ||
653 | memmove(givenmac, bufp, 20); | ||
654 | bufp += 20; lenp -= 20; | ||
655 | read_int(reveallen); | ||
656 | require_len(reveallen); | ||
657 | /* Just skip over the revealed MAC keys, which we don't need. They | ||
658 | * were published for deniability of transcripts. */ | ||
659 | bufp += reveallen; lenp -= reveallen; | ||
660 | |||
661 | /* That should be everything */ | ||
662 | if (lenp != 0) goto invval; | ||
663 | |||
664 | /* We don't take any action on this message (especially rotating | ||
665 | * keys) until we've verified the MAC on this message. To that end, | ||
666 | * we need to know which keys this message is claiming to use. */ | ||
667 | if (context->their_keyid == 0 || | ||
668 | (sender_keyid != context->their_keyid && | ||
669 | sender_keyid != context->their_keyid - 1) || | ||
670 | (recipient_keyid != context->our_keyid && | ||
671 | recipient_keyid != context->our_keyid - 1) || | ||
672 | sender_keyid == 0 || recipient_keyid == 0) { | ||
673 | goto conflict; | ||
674 | } | ||
675 | |||
676 | if (sender_keyid == context->their_keyid - 1 && | ||
677 | context->their_old_y == NULL) { | ||
678 | goto conflict; | ||
679 | } | ||
680 | |||
681 | /* These are the session keys this message is claiming to use. */ | ||
682 | sess = &(context->sesskeys | ||
683 | [context->our_keyid - recipient_keyid] | ||
684 | [context->their_keyid - sender_keyid]); | ||
685 | |||
686 | gcry_md_reset(sess->rcvmac); | ||
687 | gcry_md_write(sess->rcvmac, macstart, macend-macstart); | ||
688 | if (memcmp(givenmac, gcry_md_read(sess->rcvmac, GCRY_MD_SHA1), 20)) { | ||
689 | /* The MACs didn't match! */ | ||
690 | goto conflict; | ||
691 | } | ||
692 | sess->rcvmacused = 1; | ||
693 | |||
694 | /* Check to see that the counter is increasing; i.e. that this isn't | ||
695 | * a replay. */ | ||
696 | if (otrl_dh_cmpctr(ctr, sess->rcvctr) <= 0) { | ||
697 | goto conflict; | ||
698 | } | ||
699 | |||
700 | /* Decrypt the message */ | ||
701 | memmove(sess->rcvctr, ctr, 8); | ||
702 | err = gcry_cipher_reset(sess->rcvenc); | ||
703 | if (err) goto err; | ||
704 | err = gcry_cipher_setctr(sess->rcvenc, sess->rcvctr, 16); | ||
705 | if (err) goto err; | ||
706 | err = gcry_cipher_decrypt(sess->rcvenc, data, datalen, NULL, 0); | ||
707 | if (err) goto err; | ||
708 | |||
709 | /* See if either set of keys needs rotating */ | ||
710 | |||
711 | if (recipient_keyid == context->our_keyid) { | ||
712 | /* They're using our most recent key, so generate a new one */ | ||
713 | err = rotate_dh_keys(context); | ||
714 | if (err) goto err; | ||
715 | } | ||
716 | |||
717 | if (sender_keyid == context->their_keyid) { | ||
718 | /* They've sent us a new public key */ | ||
719 | err = rotate_y_keys(context, sender_next_y); | ||
720 | if (err) goto err; | ||
721 | } | ||
722 | |||
723 | gcry_mpi_release(sender_next_y); | ||
724 | *plaintextp = (char *)data; | ||
725 | |||
726 | /* See if there are TLVs */ | ||
727 | nul = data; | ||
728 | while (nul < data+datalen && *nul) ++nul; | ||
729 | /* If we stopped before the end, skip the NUL we stopped at */ | ||
730 | if (nul < data+datalen) ++nul; | ||
731 | *tlvsp = otrl_tlv_parse(nul, (data+datalen)-nul); | ||
732 | |||
733 | free(rawmsg); | ||
734 | return gcry_error(GPG_ERR_NO_ERROR); | ||
735 | |||
736 | invval: | ||
737 | err = gcry_error(GPG_ERR_INV_VALUE); | ||
738 | goto err; | ||
739 | conflict: | ||
740 | err = gcry_error(GPG_ERR_CONFLICT); | ||
741 | goto err; | ||
742 | err: | ||
743 | gcry_mpi_release(sender_next_y); | ||
744 | free(data); | ||
745 | free(rawmsg); | ||
746 | return err; | ||
747 | } | ||
748 | |||
749 | /* free all the fragments we have collected */ | ||
750 | gcry_error_t otrl_free_fragments(ConnContext *context) | ||
751 | { | ||
752 | if (!context) | ||
753 | { | ||
754 | /* $TODO$ better error code */ | ||
755 | return gcry_error(GPG_ERR_CONFLICT); | ||
756 | } | ||
757 | else if (context->fragments) | ||
758 | { | ||
759 | int i; | ||
760 | for (i = 0; i < context->fragment_n; ++i) | ||
761 | { | ||
762 | if (context->fragments[i]) free(context->fragments[i]); | ||
763 | } | ||
764 | free(context->fragments); | ||
765 | } | ||
766 | context->fragments = NULL; | ||
767 | context->fragment_len = 0; | ||
768 | context->fragment_n = 0; | ||
769 | context->fragment_k = 0; | ||
770 | return gcry_error(GPG_ERR_NO_ERROR); | ||
771 | } | ||
772 | |||
773 | /* start collecting fragments */ | ||
774 | static gcry_error_t otrl_malloc_fragments(ConnContext *context, int how_many) | ||
775 | { | ||
776 | if ((!context) || (how_many <= 0)) | ||
777 | { | ||
778 | return gcry_error(GPG_ERR_CONFLICT); /* $TODO$ better error code */ | ||
779 | } | ||
780 | else if (context->fragments) | ||
781 | { | ||
782 | otrl_free_fragments(context); /* shouldn't happen, but be resilient if it does */ | ||
783 | } | ||
784 | context->fragments = (char **)malloc(how_many * sizeof(char *)); | ||
785 | if (!context->fragments) | ||
786 | { | ||
787 | return gcry_error(GPG_ERR_ENOMEM); | ||
788 | } | ||
789 | else | ||
790 | { | ||
791 | int i; | ||
792 | for (i = 0; i < how_many; ++i) | ||
793 | { | ||
794 | context->fragments[i] = NULL; | ||
795 | } | ||
796 | context->fragment_n = how_many; | ||
797 | context->fragment_k = 0; | ||
798 | context->fragment_len = 0; | ||
799 | return gcry_error(GPG_ERR_NO_ERROR); | ||
800 | } | ||
801 | } | ||
802 | |||
803 | /* add a new fragment to our collection */ | ||
804 | static gcry_error_t otrl_add_fragment(ConnContext *context, int k, int len, const char *frag) | ||
805 | { | ||
806 | if ((!context) || (!frag) || (k < 0) || (context->fragment_n <= k)) | ||
807 | { | ||
808 | return gcry_error(GPG_ERR_CONFLICT); /* $TODO$ better error code */ | ||
809 | } | ||
810 | context->fragments[k] = (char*)malloc(len + 1); | ||
811 | if (! context->fragments[k]) | ||
812 | { | ||
813 | return gcry_error(GPG_ERR_ENOMEM); | ||
814 | } | ||
815 | memmove(context->fragments[k], frag, len); | ||
816 | context->fragments[k][len] = 0; | ||
817 | context->fragment_len += len; | ||
818 | context->fragment_k++; | ||
819 | return gcry_error(GPG_ERR_NO_ERROR); | ||
820 | } | ||
821 | |||
822 | /* put all the fragments together in one string */ | ||
823 | static gcry_error_t otrl_assemble_fragments(char **unfragmessagep, ConnContext *context) | ||
824 | { | ||
825 | *unfragmessagep = (char *)malloc(context->fragment_len + 1); | ||
826 | if (! *unfragmessagep) | ||
827 | { | ||
828 | otrl_free_fragments(context); | ||
829 | return gcry_error(GPG_ERR_ENOMEM); | ||
830 | } | ||
831 | else | ||
832 | { | ||
833 | int i; | ||
834 | char *p = *unfragmessagep; | ||
835 | for (i = 0; i < context->fragment_n; ++i) | ||
836 | { | ||
837 | char *q = context->fragments[i]; | ||
838 | if (!q) | ||
839 | { | ||
840 | /* inconsistent fragments */ | ||
841 | free(*unfragmessagep); | ||
842 | *unfragmessagep = NULL; | ||
843 | otrl_free_fragments(context); | ||
844 | return gcry_error(GPG_ERR_CONFLICT); /* $TODO$ better error code */ | ||
845 | } | ||
846 | while (*q) { *p = *q; p++; q++; } | ||
847 | } | ||
848 | *p = 0; | ||
849 | otrl_free_fragments(context); | ||
850 | return gcry_error(GPG_ERR_NO_ERROR); | ||
851 | } | ||
852 | } | ||
853 | |||
854 | /* Accumulate a potential fragment into the current context. */ | ||
855 | OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep, | ||
856 | ConnContext *context, const char *msg) | ||
857 | { | ||
858 | OtrlFragmentResult res = OTRL_FRAGMENT_INCOMPLETE; | ||
859 | const char *tag; | ||
860 | |||
861 | tag = strstr(msg, "?OTR,"); | ||
862 | if (! tag) | ||
863 | { /* not a fragmented message */ | ||
864 | if (context->fragments) | ||
865 | { | ||
866 | /* We didn't get all of the last one. $TODO$ send NAK */ | ||
867 | otrl_free_fragments(context); | ||
868 | } | ||
869 | res = OTRL_FRAGMENT_UNFRAGMENTED; | ||
870 | } | ||
871 | else | ||
872 | { | ||
873 | unsigned short n = 0, k = 0; | ||
874 | int start = 0, end = 0; | ||
875 | gcry_error_t err; | ||
876 | |||
877 | sscanf(tag, "?OTR,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end); | ||
878 | if (k > 0 && n > 0 && k <= n && start > 0 && end > 0 && start < end) | ||
879 | { | ||
880 | k--; | ||
881 | if (!context->fragments) | ||
882 | { | ||
883 | /* starting a new fragmented message */ | ||
884 | err = otrl_malloc_fragments(context, n); | ||
885 | if (err) return OTRL_FRAGMENT_INCOMPLETE; /* $TODO$ */ | ||
886 | } | ||
887 | else if (n != context->fragment_n) | ||
888 | { | ||
889 | /* must be starting a new message, but we didn't get | ||
890 | * all of the old one $TODO$ send a NAK */ | ||
891 | otrl_free_fragments(context); | ||
892 | err = otrl_malloc_fragments(context, n); | ||
893 | if (err) return OTRL_FRAGMENT_INCOMPLETE; /* $TODO$ */ | ||
894 | } | ||
895 | else if (context->fragments[k]) | ||
896 | { | ||
897 | /* We already got fragment K. Not likely to be a | ||
898 | * duplicate, so this must be for a new message. But | ||
899 | * we didn't get all of the old one $TODO$ send a | ||
900 | * NAK */ | ||
901 | otrl_free_fragments(context); | ||
902 | err = otrl_malloc_fragments(context, n); | ||
903 | if (err) return OTRL_FRAGMENT_INCOMPLETE; /* $TODO$ */ | ||
904 | } | ||
905 | err = otrl_add_fragment(context, k, end - start - 1, tag + start); | ||
906 | if (err) return OTRL_FRAGMENT_INCOMPLETE; /* $TODO$ */ | ||
907 | if (context->fragment_k == context->fragment_n) | ||
908 | { | ||
909 | err = otrl_assemble_fragments(unfragmessagep, context); | ||
910 | if (err) return OTRL_FRAGMENT_INCOMPLETE; /* $TODO$ */ | ||
911 | else return OTRL_FRAGMENT_COMPLETE; | ||
912 | } | ||
913 | else | ||
914 | { | ||
915 | res = OTRL_FRAGMENT_INCOMPLETE; | ||
916 | } | ||
917 | } | ||
918 | } | ||
919 | |||
920 | return res; | ||
921 | } | ||
922 | |||
923 | /* Create a fragmented message. */ | ||
924 | gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count, | ||
925 | char ***fragments, const char *message) | ||
926 | { | ||
927 | char *fragdata; | ||
928 | int fragdatalen = 0; | ||
929 | unsigned short curfrag = 0; | ||
930 | int index = 0; | ||
931 | int msglen = strlen(message); | ||
932 | int headerlen = 19; /* Should vary by number of msgs */ | ||
933 | |||
934 | char **fragmentarray = malloc(fragment_count * sizeof(char*)); | ||
935 | if(!fragmentarray) return gcry_error(GPG_ERR_ENOMEM); | ||
936 | |||
937 | /* | ||
938 | * Find the next message fragment and store it in the array. | ||
939 | */ | ||
940 | for(curfrag = 1; curfrag <= fragment_count; curfrag++) { | ||
941 | int i; | ||
942 | char *fragmentmsg; | ||
943 | |||
944 | if (msglen - index < mms - headerlen) { | ||
945 | fragdatalen = msglen - index; | ||
946 | } else { | ||
947 | fragdatalen = mms - headerlen; | ||
948 | } | ||
949 | fragdata = malloc(fragdatalen + 1); | ||
950 | if(!fragdata) { | ||
951 | for (i=0; i<curfrag-1; free(fragmentarray[i++])) {} | ||
952 | free(fragmentarray); | ||
953 | return gcry_error(GPG_ERR_ENOMEM); | ||
954 | } | ||
955 | strncpy(fragdata, message, fragdatalen); | ||
956 | fragdata[fragdatalen] = 0; | ||
957 | |||
958 | fragmentmsg = malloc(fragdatalen+headerlen+1); | ||
959 | if(!fragmentmsg) { | ||
960 | for (i=0; i<curfrag-1; free(fragmentarray[i++])) {} | ||
961 | free(fragmentarray); | ||
962 | free(fragdata); | ||
963 | return gcry_error(GPG_ERR_ENOMEM); | ||
964 | } | ||
965 | |||
966 | /* | ||
967 | * Create the actual fragment and store it in the array | ||
968 | */ | ||
969 | snprintf(fragmentmsg, fragdatalen + headerlen, "?OTR,%05hu,%05hu,%s,", curfrag, fragment_count, fragdata); | ||
970 | fragmentmsg[fragdatalen + headerlen] = 0; | ||
971 | |||
972 | fragmentarray[curfrag-1] = fragmentmsg; | ||
973 | |||
974 | free(fragdata); | ||
975 | index += fragdatalen; | ||
976 | message += fragdatalen; | ||
977 | } | ||
978 | |||
979 | *fragments = fragmentarray; | ||
980 | return gcry_error(GPG_ERR_NO_ERROR); | ||
981 | } | ||
982 | |||
983 | /* Free a string array containing fragment messages. */ | ||
984 | void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen) | ||
985 | { | ||
986 | int i; | ||
987 | char **fragmentarray = *fragments; | ||
988 | if(fragmentarray) { | ||
989 | for(i = 0; i < arraylen; i++) | ||
990 | { | ||
991 | if(fragmentarray[i]) { | ||
992 | free(fragmentarray[i]); | ||
993 | } | ||
994 | } | ||
995 | free(fragmentarray); | ||
996 | } | ||
997 | } | ||
998 | |||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/proto.h b/linden/indra/libotr/libotr-3.2.0/src/proto.h new file mode 100755 index 0000000..20b3a18 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/proto.h | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __PROTO_H__ | ||
21 | #define __PROTO_H__ | ||
22 | |||
23 | #include "context.h" | ||
24 | #include "version.h" | ||
25 | #include "tlv.h" | ||
26 | |||
27 | /* If we ever see this sequence in a plaintext message, we'll assume the | ||
28 | * other side speaks OTR, and try to establish a connection. */ | ||
29 | #define OTRL_MESSAGE_TAG_BASE " \t \t\t\t\t \t \t \t " | ||
30 | /* The following must each be of length 8 */ | ||
31 | #define OTRL_MESSAGE_TAG_V1 " \t \t \t " | ||
32 | #define OTRL_MESSAGE_TAG_V2 " \t\t \t " | ||
33 | |||
34 | /* The possible flags contained in a Data Message */ | ||
35 | #define OTRL_MSGFLAGS_IGNORE_UNREADABLE 0x01 | ||
36 | |||
37 | typedef unsigned int OtrlPolicy; | ||
38 | |||
39 | #define OTRL_POLICY_ALLOW_V1 0x01 | ||
40 | #define OTRL_POLICY_ALLOW_V2 0x02 | ||
41 | #define OTRL_POLICY_REQUIRE_ENCRYPTION 0x04 | ||
42 | #define OTRL_POLICY_SEND_WHITESPACE_TAG 0x08 | ||
43 | #define OTRL_POLICY_WHITESPACE_START_AKE 0x10 | ||
44 | #define OTRL_POLICY_ERROR_START_AKE 0x20 | ||
45 | |||
46 | #define OTRL_POLICY_VERSION_MASK (OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2) | ||
47 | |||
48 | /* For v1 compatibility */ | ||
49 | #define OTRL_POLICY_NEVER 0x00 | ||
50 | #define OTRL_POLICY_OPPORTUNISTIC \ | ||
51 | ( OTRL_POLICY_ALLOW_V1 | \ | ||
52 | OTRL_POLICY_ALLOW_V2 | \ | ||
53 | OTRL_POLICY_SEND_WHITESPACE_TAG | \ | ||
54 | OTRL_POLICY_WHITESPACE_START_AKE | \ | ||
55 | OTRL_POLICY_ERROR_START_AKE ) | ||
56 | #define OTRL_POLICY_MANUAL \ | ||
57 | ( OTRL_POLICY_ALLOW_V1 | \ | ||
58 | OTRL_POLICY_ALLOW_V2 ) | ||
59 | #define OTRL_POLICY_ALWAYS \ | ||
60 | ( OTRL_POLICY_ALLOW_V1 | \ | ||
61 | OTRL_POLICY_ALLOW_V2 | \ | ||
62 | OTRL_POLICY_REQUIRE_ENCRYPTION | \ | ||
63 | OTRL_POLICY_WHITESPACE_START_AKE | \ | ||
64 | OTRL_POLICY_ERROR_START_AKE ) | ||
65 | #define OTRL_POLICY_DEFAULT OTRL_POLICY_OPPORTUNISTIC | ||
66 | |||
67 | typedef enum { | ||
68 | OTRL_MSGTYPE_NOTOTR, | ||
69 | OTRL_MSGTYPE_TAGGEDPLAINTEXT, | ||
70 | OTRL_MSGTYPE_QUERY, | ||
71 | OTRL_MSGTYPE_DH_COMMIT, | ||
72 | OTRL_MSGTYPE_DH_KEY, | ||
73 | OTRL_MSGTYPE_REVEALSIG, | ||
74 | OTRL_MSGTYPE_SIGNATURE, | ||
75 | OTRL_MSGTYPE_V1_KEYEXCH, | ||
76 | OTRL_MSGTYPE_DATA, | ||
77 | OTRL_MSGTYPE_ERROR, | ||
78 | OTRL_MSGTYPE_UNKNOWN | ||
79 | } OtrlMessageType; | ||
80 | |||
81 | typedef enum { | ||
82 | OTRL_FRAGMENT_UNFRAGMENTED, | ||
83 | OTRL_FRAGMENT_INCOMPLETE, | ||
84 | OTRL_FRAGMENT_COMPLETE | ||
85 | } OtrlFragmentResult; | ||
86 | |||
87 | typedef enum { | ||
88 | OTRL_FRAGMENT_SEND_ALL, | ||
89 | OTRL_FRAGMENT_SEND_ALL_BUT_FIRST, | ||
90 | OTRL_FRAGMENT_SEND_ALL_BUT_LAST | ||
91 | } OtrlFragmentPolicy; | ||
92 | |||
93 | /* Initialize the OTR library. Pass the version of the API you are | ||
94 | * using. */ | ||
95 | void otrl_init(unsigned int ver_major, unsigned int ver_minor, | ||
96 | unsigned int ver_sub); | ||
97 | |||
98 | /* Shortcut */ | ||
99 | #define OTRL_INIT do { \ | ||
100 | otrl_init(OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, OTRL_VERSION_SUB); \ | ||
101 | } while(0) | ||
102 | |||
103 | /* Return a pointer to a static string containing the version number of | ||
104 | * the OTR library. */ | ||
105 | const char *otrl_version(void); | ||
106 | |||
107 | /* Return a pointer to a newly-allocated OTR query message, customized | ||
108 | * with our name. The caller should free() the result when he's done | ||
109 | * with it. */ | ||
110 | char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy); | ||
111 | |||
112 | /* Return the best version of OTR support by both sides, given an OTR | ||
113 | * Query Message and the local policy. */ | ||
114 | unsigned int otrl_proto_query_bestversion(const char *querymsg, | ||
115 | OtrlPolicy policy); | ||
116 | |||
117 | /* Locate any whitespace tag in this message, and return the best | ||
118 | * version of OTR support on both sides. Set *starttagp and *endtagp to | ||
119 | * the start and end of the located tag, so that it can be snipped out. */ | ||
120 | unsigned int otrl_proto_whitespace_bestversion(const char *msg, | ||
121 | const char **starttagp, const char **endtagp, OtrlPolicy policy); | ||
122 | |||
123 | /* Return the Message type of the given message. */ | ||
124 | OtrlMessageType otrl_proto_message_type(const char *message); | ||
125 | |||
126 | /* Create an OTR Data message. Pass the plaintext as msg, and an | ||
127 | * optional chain of TLVs. A newly-allocated string will be returned in | ||
128 | * *encmessagep. */ | ||
129 | gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context, | ||
130 | const char *msg, const OtrlTLV *tlvs, unsigned char flags); | ||
131 | |||
132 | /* Extract the flags from an otherwise unreadable Data Message. */ | ||
133 | gcry_error_t otrl_proto_data_read_flags(const char *datamsg, | ||
134 | unsigned char *flagsp); | ||
135 | |||
136 | /* Accept an OTR Data Message in datamsg. Decrypt it and put the | ||
137 | * plaintext into *plaintextp, and any TLVs into tlvsp. Put any | ||
138 | * received flags into *flagsp (if non-NULL). */ | ||
139 | gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp, | ||
140 | ConnContext *context, const char *datamsg, unsigned char *flagsp); | ||
141 | |||
142 | /* free all the fragments we have collected */ | ||
143 | gcry_error_t otrl_free_fragments(ConnContext *context); | ||
144 | |||
145 | /* Accumulate a potential fragment into the current context. */ | ||
146 | OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep, | ||
147 | ConnContext *context, const char *msg); | ||
148 | |||
149 | gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count, | ||
150 | char ***fragments, const char *message); | ||
151 | |||
152 | void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen); | ||
153 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/serial.h b/linden/indra/libotr/libotr-3.2.0/src/serial.h new file mode 100755 index 0000000..edc3184 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/serial.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __SERIAL_H__ | ||
21 | #define __SERIAL_H__ | ||
22 | |||
23 | #undef DEBUG | ||
24 | |||
25 | #ifdef DEBUG | ||
26 | |||
27 | #include <stdio.h> | ||
28 | |||
29 | #define debug_data(t,b,l) do { const unsigned char *data = (b); size_t i; \ | ||
30 | fprintf(stderr, "%s: ", (t)); \ | ||
31 | for(i=0;i<(l);++i) { \ | ||
32 | fprintf(stderr, "%02x", data[i]); \ | ||
33 | } \ | ||
34 | fprintf(stderr, "\n"); \ | ||
35 | } while(0) | ||
36 | |||
37 | #define debug_int(t,b) do { const unsigned char *data = (b); \ | ||
38 | unsigned int v = \ | ||
39 | (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \ | ||
40 | fprintf(stderr, "%s: %u (0x%x)\n", (t), v, v); \ | ||
41 | } while(0) | ||
42 | |||
43 | #else | ||
44 | #define debug_data(t,b,l) | ||
45 | #define debug_int(t,b) | ||
46 | #endif | ||
47 | |||
48 | #define write_int(x) do { \ | ||
49 | bufp[0] = ((x) >> 24) & 0xff; \ | ||
50 | bufp[1] = ((x) >> 16) & 0xff; \ | ||
51 | bufp[2] = ((x) >> 8) & 0xff; \ | ||
52 | bufp[3] = (x) & 0xff; \ | ||
53 | bufp += 4; lenp -= 4; \ | ||
54 | } while(0) | ||
55 | |||
56 | #define write_mpi(x,nx,dx) do { \ | ||
57 | write_int(nx); \ | ||
58 | gcry_mpi_print(format, bufp, lenp, NULL, (x)); \ | ||
59 | debug_data((dx), bufp, (nx)); \ | ||
60 | bufp += (nx); lenp -= (nx); \ | ||
61 | } while(0) | ||
62 | |||
63 | #define require_len(l) do { \ | ||
64 | if (lenp < (l)) goto invval; \ | ||
65 | } while(0) | ||
66 | |||
67 | #define read_int(x) do { \ | ||
68 | require_len(4); \ | ||
69 | (x) = (bufp[0] << 24) | (bufp[1] << 16) | (bufp[2] << 8) | bufp[3]; \ | ||
70 | bufp += 4; lenp -= 4; \ | ||
71 | } while(0) | ||
72 | |||
73 | #define read_mpi(x) do { \ | ||
74 | size_t mpilen; \ | ||
75 | read_int(mpilen); \ | ||
76 | if (mpilen) { \ | ||
77 | require_len(mpilen); \ | ||
78 | gcry_mpi_scan(&(x), GCRYMPI_FMT_USG, bufp, mpilen, NULL); \ | ||
79 | } else { \ | ||
80 | (x) = gcry_mpi_set_ui(NULL, 0); \ | ||
81 | } \ | ||
82 | bufp += mpilen; lenp -= mpilen; \ | ||
83 | } while(0) | ||
84 | |||
85 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/sm.c b/linden/indra/libotr/libotr-3.2.0/src/sm.c new file mode 100755 index 0000000..318b461 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/sm.c | |||
@@ -0,0 +1,929 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* system headers */ | ||
21 | #include <stdlib.h> | ||
22 | #include <stdio.h> | ||
23 | #include <sys/types.h> | ||
24 | |||
25 | /* libgcrypt headers */ | ||
26 | #include <gcrypt.h> | ||
27 | |||
28 | /* libotr headers */ | ||
29 | #include "sm.h" | ||
30 | #include "serial.h" | ||
31 | |||
32 | static const int SM_MSG1_LEN = 6; | ||
33 | static const int SM_MSG2_LEN = 11; | ||
34 | static const int SM_MSG3_LEN = 8; | ||
35 | static const int SM_MSG4_LEN = 3; | ||
36 | |||
37 | /* The modulus p */ | ||
38 | static const char* SM_MODULUS_S = "0x" | ||
39 | "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" | ||
40 | "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" | ||
41 | "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" | ||
42 | "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" | ||
43 | "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" | ||
44 | "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" | ||
45 | "83655D23DCA3AD961C62F356208552BB9ED529077096966D" | ||
46 | "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; | ||
47 | /* The order of the group q = (p-1)/2 */ | ||
48 | static const char* SM_ORDER_S = "0x" | ||
49 | "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" | ||
50 | "948127044533E63A0105DF531D89CD9128A5043CC71A026E" | ||
51 | "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" | ||
52 | "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" | ||
53 | "F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9E" | ||
54 | "E1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AF" | ||
55 | "C1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36" | ||
56 | "B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF"; | ||
57 | static const char *SM_GENERATOR_S = "0x02"; | ||
58 | static const int SM_MOD_LEN_BITS = 1536; | ||
59 | static const int SM_MOD_LEN_BYTES = 192; | ||
60 | |||
61 | static gcry_mpi_t SM_MODULUS = NULL; | ||
62 | static gcry_mpi_t SM_GENERATOR = NULL; | ||
63 | static gcry_mpi_t SM_ORDER = NULL; | ||
64 | static gcry_mpi_t SM_MODULUS_MINUS_2 = NULL; | ||
65 | |||
66 | /* | ||
67 | * Call this once, at plugin load time. It sets up the modulus and | ||
68 | * generator MPIs. | ||
69 | */ | ||
70 | void otrl_sm_init(void) | ||
71 | { | ||
72 | gcry_check_version(NULL); | ||
73 | gcry_mpi_scan(&SM_MODULUS, GCRYMPI_FMT_HEX, SM_MODULUS_S, 0, NULL); | ||
74 | gcry_mpi_scan(&SM_ORDER, GCRYMPI_FMT_HEX, SM_ORDER_S, 0, NULL); | ||
75 | gcry_mpi_scan(&SM_GENERATOR, GCRYMPI_FMT_HEX, SM_GENERATOR_S, | ||
76 | 0, NULL); | ||
77 | SM_MODULUS_MINUS_2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
78 | gcry_mpi_sub_ui(SM_MODULUS_MINUS_2, SM_MODULUS, 2); | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * Initialize the fields of a SM state. | ||
83 | */ | ||
84 | void otrl_sm_state_new(OtrlSMState *smst) | ||
85 | { | ||
86 | smst->secret = NULL; | ||
87 | smst->x2 = NULL; | ||
88 | smst->x3 = NULL; | ||
89 | smst->g1 = NULL; | ||
90 | smst->g2 = NULL; | ||
91 | smst->g3 = NULL; | ||
92 | smst->g3o = NULL; | ||
93 | smst->p = NULL; | ||
94 | smst->q = NULL; | ||
95 | smst->pab = NULL; | ||
96 | smst->qab = NULL; | ||
97 | smst->nextExpected = OTRL_SMP_EXPECT1; | ||
98 | smst->received_question = 0; | ||
99 | smst->sm_prog_state = OTRL_SMP_PROG_OK; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Initialize the fields of a SM state. Called the first time that | ||
104 | * a user begins an SMP session. | ||
105 | */ | ||
106 | void otrl_sm_state_init(OtrlSMState *smst) | ||
107 | { | ||
108 | otrl_sm_state_free(smst); | ||
109 | smst->secret = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
110 | smst->x2 = NULL; | ||
111 | smst->x3 = NULL; | ||
112 | smst->g1 = gcry_mpi_copy(SM_GENERATOR); | ||
113 | smst->g2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
114 | smst->g3 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
115 | smst->g3o = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
116 | smst->p = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
117 | smst->q = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
118 | smst->pab = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
119 | smst->qab = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
120 | smst->received_question = 0; | ||
121 | smst->sm_prog_state = OTRL_SMP_PROG_OK; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Initialize the fields of a SM message1. | ||
126 | * [0] = g2a, [1] = c2, [2] = d2, [3] = g3a, [4] = c3, [5] = d3 | ||
127 | */ | ||
128 | void otrl_sm_msg1_init(gcry_mpi_t **msg1) | ||
129 | { | ||
130 | gcry_mpi_t *msg = malloc(SM_MSG1_LEN * sizeof(gcry_mpi_t)); | ||
131 | msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
132 | msg[1] = NULL; | ||
133 | msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
134 | msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
135 | msg[4] = NULL; | ||
136 | msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
137 | |||
138 | *msg1 = msg; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Initialize the fields of a SM message2. | ||
143 | * [0] = g2b, [1] = c2, [2] = d2, [3] = g3b, [4] = c3, [5] = d3 | ||
144 | * [6] = pb, [7] = qb, [8] = cp, [9] = d5, [10] = d6 | ||
145 | */ | ||
146 | void otrl_sm_msg2_init(gcry_mpi_t **msg2) | ||
147 | { | ||
148 | gcry_mpi_t *msg = malloc(SM_MSG2_LEN * sizeof(gcry_mpi_t)); | ||
149 | msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
150 | msg[1] = NULL; | ||
151 | msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
152 | msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
153 | msg[4] = NULL; | ||
154 | msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
155 | msg[6] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
156 | msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
157 | msg[8] = NULL; | ||
158 | msg[9] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
159 | msg[10] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
160 | |||
161 | *msg2 = msg; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Initialize the fields of a SM message3. | ||
166 | * [0] = pa, [1] = qa, [2] = cp, [3] = d5, [4] = d6, [5] = ra, | ||
167 | * [6] = cr, [7] = d7 | ||
168 | */ | ||
169 | void otrl_sm_msg3_init(gcry_mpi_t **msg3) | ||
170 | { | ||
171 | gcry_mpi_t *msg = malloc(SM_MSG3_LEN * sizeof(gcry_mpi_t)); | ||
172 | msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
173 | msg[1] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
174 | msg[2] = NULL; | ||
175 | msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
176 | msg[4] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
177 | msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
178 | msg[6] = NULL; | ||
179 | msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
180 | |||
181 | *msg3 = msg; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Initialize the fields of a SM message4. | ||
186 | * [0] = rb, [1] = cr, [2] = d7 | ||
187 | */ | ||
188 | void otrl_sm_msg4_init(gcry_mpi_t **msg4) | ||
189 | { | ||
190 | gcry_mpi_t *msg = malloc(SM_MSG4_LEN * sizeof(gcry_mpi_t)); | ||
191 | msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
192 | msg[1] = NULL; | ||
193 | msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
194 | |||
195 | *msg4 = msg; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Deallocate the contents of a OtrlSMState (but not the OtrlSMState | ||
200 | * itself) | ||
201 | */ | ||
202 | void otrl_sm_state_free(OtrlSMState *smst) | ||
203 | { | ||
204 | gcry_mpi_release(smst->secret); | ||
205 | gcry_mpi_release(smst->x2); | ||
206 | gcry_mpi_release(smst->x3); | ||
207 | gcry_mpi_release(smst->g1); | ||
208 | gcry_mpi_release(smst->g2); | ||
209 | gcry_mpi_release(smst->g3); | ||
210 | gcry_mpi_release(smst->g3o); | ||
211 | gcry_mpi_release(smst->p); | ||
212 | gcry_mpi_release(smst->q); | ||
213 | gcry_mpi_release(smst->pab); | ||
214 | gcry_mpi_release(smst->qab); | ||
215 | otrl_sm_state_new(smst); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Deallocate the contents of a message | ||
220 | */ | ||
221 | void otrl_sm_msg_free(gcry_mpi_t **message, int msglen) | ||
222 | { | ||
223 | gcry_mpi_t *msg = *message; | ||
224 | int i; | ||
225 | for (i=0; i<msglen; i++) { | ||
226 | gcry_mpi_release(msg[i]); | ||
227 | } | ||
228 | free(msg); | ||
229 | *message = NULL; | ||
230 | } | ||
231 | |||
232 | static gcry_mpi_t randomExponent(void) | ||
233 | { | ||
234 | unsigned char *secbuf = NULL; | ||
235 | gcry_mpi_t randexpon = NULL; | ||
236 | |||
237 | /* Generate a random exponent */ | ||
238 | secbuf = gcry_random_bytes_secure(SM_MOD_LEN_BYTES, GCRY_STRONG_RANDOM); | ||
239 | gcry_mpi_scan(&randexpon, GCRYMPI_FMT_USG, secbuf, SM_MOD_LEN_BYTES, NULL); | ||
240 | gcry_free(secbuf); | ||
241 | |||
242 | return randexpon; | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * Hash one or two mpis. To hash only one mpi, b may be set to NULL. | ||
247 | */ | ||
248 | static gcry_error_t otrl_sm_hash(gcry_mpi_t* hash, int version, | ||
249 | const gcry_mpi_t a, const gcry_mpi_t b) | ||
250 | { | ||
251 | unsigned char* input; | ||
252 | unsigned char output[SM_DIGEST_SIZE]; | ||
253 | size_t sizea; | ||
254 | size_t sizeb; | ||
255 | size_t totalsize; | ||
256 | unsigned char* dataa; | ||
257 | unsigned char* datab; | ||
258 | |||
259 | gcry_mpi_aprint(GCRYMPI_FMT_USG, &dataa, &sizea, a); | ||
260 | totalsize = 1 + 4 + sizea; | ||
261 | if (b) { | ||
262 | gcry_mpi_aprint(GCRYMPI_FMT_USG, &datab, &sizeb, b); | ||
263 | totalsize += 4 + sizeb; | ||
264 | } else { | ||
265 | sizeb = 0; | ||
266 | } | ||
267 | |||
268 | input = malloc(totalsize); | ||
269 | input[0] = (unsigned char)version; | ||
270 | input[1] = (unsigned char)((sizea >> 24) & 0xFF); | ||
271 | input[2] = (unsigned char)((sizea >> 16) & 0xFF); | ||
272 | input[3] = (unsigned char)((sizea >> 8) & 0xFF); | ||
273 | input[4] = (unsigned char)(sizea & 0xFF); | ||
274 | memmove(input + 5, dataa, sizea); | ||
275 | if (b) { | ||
276 | input[5 + sizea] = (unsigned char)((sizeb >> 24) & 0xFF); | ||
277 | input[6 + sizea] = (unsigned char)((sizeb >> 16) & 0xFF); | ||
278 | input[7 + sizea] = (unsigned char)((sizeb >> 8) & 0xFF); | ||
279 | input[8 + sizea] = (unsigned char)(sizeb & 0xFF); | ||
280 | memmove(input + 9 + sizea, datab, sizeb); | ||
281 | } | ||
282 | |||
283 | gcry_md_hash_buffer(SM_HASH_ALGORITHM, output, input, totalsize); | ||
284 | gcry_mpi_scan(hash, GCRYMPI_FMT_USG, output, SM_DIGEST_SIZE, NULL); | ||
285 | free(input); | ||
286 | input = NULL; | ||
287 | |||
288 | /* free memory */ | ||
289 | gcry_free(dataa); | ||
290 | if (b) gcry_free(datab); | ||
291 | |||
292 | return gcry_error(GPG_ERR_NO_ERROR); | ||
293 | } | ||
294 | |||
295 | /* This method should be passed a pointer to an uninitialized buffer, | ||
296 | * and a list of mpis with a list length. When returns, the buffer will | ||
297 | * point to newly-allocated memory (using malloc) containing a | ||
298 | * reversible serialization. */ | ||
299 | static gcry_error_t serialize_mpi_array(unsigned char **buffer, int *buflen, | ||
300 | unsigned int count, gcry_mpi_t *mpis) | ||
301 | { | ||
302 | size_t totalsize = 0, lenp, nextsize; | ||
303 | unsigned int i, j; | ||
304 | size_t *list_sizes = malloc(count * sizeof(size_t)); | ||
305 | unsigned char **tempbuffer = malloc(count * sizeof(unsigned char *)); | ||
306 | unsigned char *bufp; | ||
307 | |||
308 | for (i=0; i<count; i++) { | ||
309 | gcry_mpi_aprint(GCRYMPI_FMT_USG, &(tempbuffer[i]), &(list_sizes[i]), | ||
310 | mpis[i]); | ||
311 | totalsize += list_sizes[i]; | ||
312 | } | ||
313 | |||
314 | *buflen = (count+1)*4 + totalsize; | ||
315 | *buffer = malloc(*buflen * sizeof(char)); | ||
316 | |||
317 | bufp = *buffer; | ||
318 | lenp = totalsize; | ||
319 | |||
320 | write_int(count); | ||
321 | for(i=0; i<count; i++) | ||
322 | { | ||
323 | nextsize = list_sizes[i]; | ||
324 | write_int(nextsize); | ||
325 | |||
326 | for(j=0; j<nextsize; j++) | ||
327 | bufp[j] = tempbuffer[i][j]; | ||
328 | |||
329 | bufp += nextsize; | ||
330 | lenp -= nextsize; | ||
331 | gcry_free(tempbuffer[i]); | ||
332 | } | ||
333 | free(tempbuffer); | ||
334 | free(list_sizes); | ||
335 | |||
336 | return gcry_error(GPG_ERR_NO_ERROR); | ||
337 | } | ||
338 | |||
339 | /* Takes a buffer containing serialized and concatenated mpis | ||
340 | * and converts it to an array of gcry_mpi_t structs. | ||
341 | * The buffer is assumed to consist of a 4-byte int containing the | ||
342 | * number of mpis in the array, followed by {size, data} pairs for | ||
343 | * each mpi. If malformed, method returns GCRY_ERROR_INV_VALUE */ | ||
344 | static gcry_error_t unserialize_mpi_array(gcry_mpi_t **mpis, | ||
345 | unsigned int expcount, const unsigned char *buffer, const int buflen) | ||
346 | { | ||
347 | unsigned int i; | ||
348 | int lenp = buflen; | ||
349 | unsigned int thecount = 0; | ||
350 | const unsigned char* bufp = buffer; | ||
351 | *mpis = NULL; | ||
352 | |||
353 | read_int(thecount); | ||
354 | if (thecount != expcount) goto invval; | ||
355 | |||
356 | *mpis = malloc(thecount * sizeof(gcry_mpi_t)); | ||
357 | |||
358 | for (i=0; i<thecount; i++) { | ||
359 | (*mpis)[i] = NULL; | ||
360 | } | ||
361 | |||
362 | for (i=0; i<thecount; i++) { | ||
363 | read_mpi((*mpis)[i]); | ||
364 | } | ||
365 | |||
366 | return gcry_error(GPG_ERR_NO_ERROR); | ||
367 | |||
368 | invval: | ||
369 | if (*mpis) { | ||
370 | for (i=0; i<thecount; i++) { | ||
371 | gcry_mpi_release((*mpis)[i]); | ||
372 | } | ||
373 | free(*mpis); | ||
374 | *mpis = NULL; | ||
375 | } | ||
376 | return gcry_error(GPG_ERR_INV_VALUE); | ||
377 | } | ||
378 | |||
379 | /* Check that an MPI is in the right range to be a (non-unit) group | ||
380 | * element */ | ||
381 | static int check_group_elem(gcry_mpi_t g) | ||
382 | { | ||
383 | if (gcry_mpi_cmp_ui(g, 2) < 0 || | ||
384 | gcry_mpi_cmp(g, SM_MODULUS_MINUS_2) > 0) { | ||
385 | return 1; | ||
386 | } | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | /* Check that an MPI is in the right range to be a (non-zero) exponent */ | ||
391 | static int check_expon(gcry_mpi_t x) | ||
392 | { | ||
393 | if (gcry_mpi_cmp_ui(x, 1) < 0 || | ||
394 | gcry_mpi_cmp(x, SM_ORDER) >= 0) { | ||
395 | return 1; | ||
396 | } | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | /* | ||
401 | * Proof of knowledge of a discrete logarithm | ||
402 | */ | ||
403 | static gcry_error_t otrl_sm_proof_know_log(gcry_mpi_t *c, gcry_mpi_t *d, const gcry_mpi_t g, const gcry_mpi_t x, int version) | ||
404 | { | ||
405 | gcry_mpi_t r = randomExponent(); | ||
406 | gcry_mpi_t temp = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
407 | gcry_mpi_powm(temp, g, r, SM_MODULUS); | ||
408 | otrl_sm_hash(c, version, temp, NULL); | ||
409 | gcry_mpi_mulm(temp, x, *c, SM_ORDER); | ||
410 | gcry_mpi_subm(*d, r, temp, SM_ORDER); | ||
411 | gcry_mpi_release(temp); | ||
412 | gcry_mpi_release(r); | ||
413 | |||
414 | return gcry_error(GPG_ERR_NO_ERROR); | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Verify a proof of knowledge of a discrete logarithm. Checks that c = h(g^d x^c) | ||
419 | */ | ||
420 | static int otrl_sm_check_know_log(const gcry_mpi_t c, const gcry_mpi_t d, const gcry_mpi_t g, const gcry_mpi_t x, int version) | ||
421 | { | ||
422 | int comp; | ||
423 | |||
424 | gcry_mpi_t gd = gcry_mpi_new(SM_MOD_LEN_BITS); /* g^d */ | ||
425 | gcry_mpi_t xc = gcry_mpi_new(SM_MOD_LEN_BITS); /* x^c */ | ||
426 | gcry_mpi_t gdxc = gcry_mpi_new(SM_MOD_LEN_BITS); /* (g^d x^c) */ | ||
427 | gcry_mpi_t hgdxc = NULL; /* h(g^d x^c) */ | ||
428 | |||
429 | gcry_mpi_powm(gd, g, d, SM_MODULUS); | ||
430 | gcry_mpi_powm(xc, x, c, SM_MODULUS); | ||
431 | gcry_mpi_mulm(gdxc, gd, xc, SM_MODULUS); | ||
432 | otrl_sm_hash(&hgdxc, version, gdxc, NULL); | ||
433 | |||
434 | comp = gcry_mpi_cmp(hgdxc, c); | ||
435 | gcry_mpi_release(gd); | ||
436 | gcry_mpi_release(xc); | ||
437 | gcry_mpi_release(gdxc); | ||
438 | gcry_mpi_release(hgdxc); | ||
439 | |||
440 | return comp; | ||
441 | } | ||
442 | |||
443 | /* | ||
444 | * Proof of knowledge of coordinates with first components being equal | ||
445 | */ | ||
446 | static gcry_error_t otrl_sm_proof_equal_coords(gcry_mpi_t *c, gcry_mpi_t *d1, gcry_mpi_t *d2, const OtrlSMState *state, const gcry_mpi_t r, int version) | ||
447 | { | ||
448 | gcry_mpi_t r1 = randomExponent(); | ||
449 | gcry_mpi_t r2 = randomExponent(); | ||
450 | gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
451 | gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
452 | |||
453 | /* Compute the value of c, as c = h(g3^r1, g1^r1 g2^r2) */ | ||
454 | gcry_mpi_powm(temp1, state->g1, r1, SM_MODULUS); | ||
455 | gcry_mpi_powm(temp2, state->g2, r2, SM_MODULUS); | ||
456 | gcry_mpi_mulm(temp2, temp1, temp2, SM_MODULUS); | ||
457 | gcry_mpi_powm(temp1, state->g3, r1, SM_MODULUS); | ||
458 | otrl_sm_hash(c, version, temp1, temp2); | ||
459 | |||
460 | /* Compute the d values, as d1 = r1 - r c, d2 = r2 - secret c */ | ||
461 | gcry_mpi_mulm(temp1, r, *c, SM_ORDER); | ||
462 | gcry_mpi_subm(*d1, r1, temp1, SM_ORDER); | ||
463 | |||
464 | gcry_mpi_mulm(temp1, state->secret, *c, SM_ORDER); | ||
465 | gcry_mpi_subm(*d2, r2, temp1, SM_ORDER); | ||
466 | |||
467 | /* All clear */ | ||
468 | gcry_mpi_release(r1); | ||
469 | gcry_mpi_release(r2); | ||
470 | gcry_mpi_release(temp1); | ||
471 | gcry_mpi_release(temp2); | ||
472 | return gcry_error(GPG_ERR_NO_ERROR); | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * Verify a proof of knowledge of coordinates with first components being equal | ||
477 | */ | ||
478 | static gcry_error_t otrl_sm_check_equal_coords(const gcry_mpi_t c, const gcry_mpi_t d1, const gcry_mpi_t d2, const gcry_mpi_t p, const gcry_mpi_t q, const OtrlSMState *state, int version) | ||
479 | { | ||
480 | int comp; | ||
481 | |||
482 | gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
483 | gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
484 | gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
485 | gcry_mpi_t cprime = NULL; | ||
486 | |||
487 | /* To verify, we test that hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) = c | ||
488 | * If indeed c = hash(g3^r1, g1^r1 g2^r2), d1 = r1 - r*c, | ||
489 | * d2 = r2 - secret*c. And if indeed p = g3^r, q = g1^r * g2^secret | ||
490 | * Then we should have that: | ||
491 | * hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) | ||
492 | * = hash(g3^(r1 - r*c + r*c), g1^(r1 - r*c + q*c) * | ||
493 | * g2^(r2 - secret*c + secret*c)) | ||
494 | * = hash(g3^r1, g1^r1 g2^r2) | ||
495 | * = c | ||
496 | */ | ||
497 | gcry_mpi_powm(temp2, state->g3, d1, SM_MODULUS); | ||
498 | gcry_mpi_powm(temp3, p, c, SM_MODULUS); | ||
499 | gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS); | ||
500 | |||
501 | gcry_mpi_powm(temp2, state->g1, d1, SM_MODULUS); | ||
502 | gcry_mpi_powm(temp3, state->g2, d2, SM_MODULUS); | ||
503 | gcry_mpi_mulm(temp2, temp2, temp3, SM_MODULUS); | ||
504 | gcry_mpi_powm(temp3, q, c, SM_MODULUS); | ||
505 | gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS); | ||
506 | |||
507 | otrl_sm_hash(&cprime, version, temp1, temp2); | ||
508 | |||
509 | comp = gcry_mpi_cmp(c, cprime); | ||
510 | gcry_mpi_release(temp1); | ||
511 | gcry_mpi_release(temp2); | ||
512 | gcry_mpi_release(temp3); | ||
513 | gcry_mpi_release(cprime); | ||
514 | |||
515 | return comp; | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * Proof of knowledge of logs with exponents being equal | ||
520 | */ | ||
521 | static gcry_error_t otrl_sm_proof_equal_logs(gcry_mpi_t *c, gcry_mpi_t *d, OtrlSMState *state, int version) | ||
522 | { | ||
523 | gcry_mpi_t r = randomExponent(); | ||
524 | gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
525 | gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
526 | |||
527 | /* Compute the value of c, as c = h(g1^r, (Qa/Qb)^r) */ | ||
528 | gcry_mpi_powm(temp1, state->g1, r, SM_MODULUS); | ||
529 | gcry_mpi_powm(temp2, state->qab, r, SM_MODULUS); | ||
530 | otrl_sm_hash(c, version, temp1, temp2); | ||
531 | |||
532 | /* Compute the d values, as d = r - x3 c */ | ||
533 | gcry_mpi_mulm(temp1, state->x3, *c, SM_ORDER); | ||
534 | gcry_mpi_subm(*d, r, temp1, SM_ORDER); | ||
535 | |||
536 | /* All clear */ | ||
537 | gcry_mpi_release(r); | ||
538 | gcry_mpi_release(temp1); | ||
539 | gcry_mpi_release(temp2); | ||
540 | return gcry_error(GPG_ERR_NO_ERROR); | ||
541 | } | ||
542 | |||
543 | /* | ||
544 | * Verify a proof of knowledge of logs with exponents being equal | ||
545 | */ | ||
546 | static gcry_error_t otrl_sm_check_equal_logs(const gcry_mpi_t c, const gcry_mpi_t d, const gcry_mpi_t r, const OtrlSMState *state, int version) | ||
547 | { | ||
548 | int comp; | ||
549 | |||
550 | gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
551 | gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
552 | gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
553 | gcry_mpi_t cprime = NULL; | ||
554 | |||
555 | /* Here, we recall the exponents used to create g3. | ||
556 | * If we have previously seen g3o = g1^x where x is unknown | ||
557 | * during the DH exchange to produce g3, then we may proceed with: | ||
558 | * | ||
559 | * To verify, we test that hash(g1^d * g3o^c, qab^d * r^c) = c | ||
560 | * If indeed c = hash(g1^r1, qab^r1), d = r1- x * c | ||
561 | * And if indeed r = qab^x | ||
562 | * Then we should have that: | ||
563 | * hash(g1^d * g3o^c, qab^d r^c) | ||
564 | * = hash(g1^(r1 - x*c + x*c), qab^(r1 - x*c + x*c)) | ||
565 | * = hash(g1^r1, qab^r1) | ||
566 | * = c | ||
567 | */ | ||
568 | gcry_mpi_powm(temp2, state->g1, d, SM_MODULUS); | ||
569 | gcry_mpi_powm(temp3, state->g3o, c, SM_MODULUS); | ||
570 | gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS); | ||
571 | |||
572 | gcry_mpi_powm(temp3, state->qab, d, SM_MODULUS); | ||
573 | gcry_mpi_powm(temp2, r, c, SM_MODULUS); | ||
574 | gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS); | ||
575 | |||
576 | otrl_sm_hash(&cprime, version, temp1, temp2); | ||
577 | |||
578 | comp = gcry_mpi_cmp(c, cprime); | ||
579 | gcry_mpi_release(temp1); | ||
580 | gcry_mpi_release(temp2); | ||
581 | gcry_mpi_release(temp3); | ||
582 | gcry_mpi_release(cprime); | ||
583 | |||
584 | return comp; | ||
585 | } | ||
586 | |||
587 | /* Create first message in SMP exchange. Input is Alice's secret value | ||
588 | * which this protocol aims to compare to Bob's. Output is a serialized | ||
589 | * mpi array whose elements correspond to the following: | ||
590 | * [0] = g2a, Alice's half of DH exchange to determine g2 | ||
591 | * [1] = c2, [2] = d2, Alice's ZK proof of knowledge of g2a exponent | ||
592 | * [3] = g3a, Alice's half of DH exchange to determine g3 | ||
593 | * [4] = c3, [5] = d3, Alice's ZK proof of knowledge of g3a exponent */ | ||
594 | gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate, | ||
595 | const unsigned char* secret, int secretlen, | ||
596 | unsigned char** output, int* outputlen) | ||
597 | { | ||
598 | /* Initialize the sm state or update the secret */ | ||
599 | gcry_mpi_t secret_mpi = NULL; | ||
600 | gcry_mpi_t *msg1; | ||
601 | |||
602 | *output = NULL; | ||
603 | *outputlen = 0; | ||
604 | |||
605 | gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL); | ||
606 | |||
607 | if (! astate->g1) { | ||
608 | otrl_sm_state_init(astate); | ||
609 | } | ||
610 | gcry_mpi_set(astate->secret, secret_mpi); | ||
611 | gcry_mpi_release(secret_mpi); | ||
612 | astate->received_question = 0; | ||
613 | |||
614 | otrl_sm_msg1_init(&msg1); | ||
615 | |||
616 | astate->x2 = randomExponent(); | ||
617 | astate->x3 = randomExponent(); | ||
618 | |||
619 | gcry_mpi_powm(msg1[0], astate->g1, astate->x2, SM_MODULUS); | ||
620 | otrl_sm_proof_know_log(&(msg1[1]), &(msg1[2]), astate->g1, astate->x2, 1); | ||
621 | |||
622 | gcry_mpi_powm(msg1[3], astate->g1, astate->x3, SM_MODULUS); | ||
623 | otrl_sm_proof_know_log(&(msg1[4]), &(msg1[5]), astate->g1, astate->x3, 2); | ||
624 | |||
625 | serialize_mpi_array(output, outputlen, SM_MSG1_LEN, msg1); | ||
626 | otrl_sm_msg_free(&msg1, SM_MSG1_LEN); | ||
627 | astate->sm_prog_state = OTRL_SMP_PROG_OK; | ||
628 | return gcry_error(GPG_ERR_NO_ERROR); | ||
629 | } | ||
630 | |||
631 | /* Receive the first message in SMP exchange, which was generated by | ||
632 | * otrl_sm_step1. Input is saved until the user inputs their secret | ||
633 | * information. No output. */ | ||
634 | gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, int received_question) | ||
635 | { | ||
636 | gcry_mpi_t *msg1; | ||
637 | gcry_error_t err; | ||
638 | |||
639 | /* Initialize the sm state if needed */ | ||
640 | if (! bstate->g1) { | ||
641 | otrl_sm_state_init(bstate); | ||
642 | } | ||
643 | bstate->received_question = received_question; | ||
644 | bstate->sm_prog_state = OTRL_SMP_PROG_CHEATED; | ||
645 | |||
646 | /* Read from input to find the mpis */ | ||
647 | err = unserialize_mpi_array(&msg1, SM_MSG1_LEN, input, inputlen); | ||
648 | |||
649 | if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; | ||
650 | |||
651 | if (check_group_elem(msg1[0]) || check_expon(msg1[2]) || | ||
652 | check_group_elem(msg1[3]) || check_expon(msg1[5])) { | ||
653 | return gcry_error(GPG_ERR_INV_VALUE); | ||
654 | } | ||
655 | |||
656 | /* Store Alice's g3a value for later in the protocol */ | ||
657 | gcry_mpi_set(bstate->g3o, msg1[3]); | ||
658 | |||
659 | /* Verify Alice's proofs */ | ||
660 | if (otrl_sm_check_know_log(msg1[1], msg1[2], bstate->g1, msg1[0], 1) || | ||
661 | otrl_sm_check_know_log(msg1[4], msg1[5], bstate->g1, msg1[3], 2)) { | ||
662 | return gcry_error(GPG_ERR_INV_VALUE); | ||
663 | } | ||
664 | |||
665 | /* Create Bob's half of the generators g2 and g3 */ | ||
666 | bstate->x2 = randomExponent(); | ||
667 | bstate->x3 = randomExponent(); | ||
668 | |||
669 | /* Combine the two halves from Bob and Alice and determine g2 and g3 */ | ||
670 | gcry_mpi_powm(bstate->g2, msg1[0], bstate->x2, SM_MODULUS); | ||
671 | gcry_mpi_powm(bstate->g3, msg1[3], bstate->x3, SM_MODULUS); | ||
672 | |||
673 | bstate->sm_prog_state = OTRL_SMP_PROG_OK; | ||
674 | return gcry_error(GPG_ERR_NO_ERROR); | ||
675 | } | ||
676 | |||
677 | /* Create second message in SMP exchange. Input is Bob's secret value. | ||
678 | * Information from earlier steps in the exchange is taken from Bob's | ||
679 | * state. Output is a serialized mpi array whose elements correspond | ||
680 | * to the following: | ||
681 | * [0] = g2b, Bob's half of DH exchange to determine g2 | ||
682 | * [1] = c2, [2] = d2, Bob's ZK proof of knowledge of g2b exponent | ||
683 | * [3] = g3b, Bob's half of DH exchange to determine g3 | ||
684 | * [4] = c3, [5] = d3, Bob's ZK proof of knowledge of g3b exponent | ||
685 | * [6] = pb, [7] = qb, Bob's halves of the (Pa/Pb) and (Qa/Qb) values | ||
686 | * [8] = cp, [9] = d5, [10] = d6, Bob's ZK proof that pb, qb formed correctly */ | ||
687 | gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret, int secretlen, unsigned char **output, int* outputlen) | ||
688 | { | ||
689 | /* Convert the given secret to the proper form and store it */ | ||
690 | gcry_mpi_t r, qb1, qb2; | ||
691 | gcry_mpi_t *msg2; | ||
692 | gcry_mpi_t secret_mpi = NULL; | ||
693 | |||
694 | *output = NULL; | ||
695 | *outputlen = 0; | ||
696 | |||
697 | gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL); | ||
698 | gcry_mpi_set(bstate->secret, secret_mpi); | ||
699 | gcry_mpi_release(secret_mpi); | ||
700 | |||
701 | otrl_sm_msg2_init(&msg2); | ||
702 | |||
703 | gcry_mpi_powm(msg2[0], bstate->g1, bstate->x2, SM_MODULUS); | ||
704 | otrl_sm_proof_know_log(&(msg2[1]), &(msg2[2]), bstate->g1, bstate->x2, 3); | ||
705 | |||
706 | gcry_mpi_powm(msg2[3], bstate->g1, bstate->x3, SM_MODULUS); | ||
707 | otrl_sm_proof_know_log(&(msg2[4]), &(msg2[5]), bstate->g1, bstate->x3, 4); | ||
708 | |||
709 | /* Calculate P and Q values for Bob */ | ||
710 | r = randomExponent(); | ||
711 | qb1 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
712 | qb2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
713 | gcry_mpi_powm(bstate->p, bstate->g3, r, SM_MODULUS); | ||
714 | gcry_mpi_set(msg2[6], bstate->p); | ||
715 | gcry_mpi_powm(qb1, bstate->g1, r, SM_MODULUS); | ||
716 | gcry_mpi_powm(qb2, bstate->g2, bstate->secret, SM_MODULUS); | ||
717 | gcry_mpi_mulm(bstate->q, qb1, qb2, SM_MODULUS); | ||
718 | gcry_mpi_set(msg2[7], bstate->q); | ||
719 | |||
720 | otrl_sm_proof_equal_coords(&(msg2[8]), &(msg2[9]), &(msg2[10]), bstate, r, 5); | ||
721 | |||
722 | /* Convert to serialized form */ | ||
723 | serialize_mpi_array(output, outputlen, SM_MSG2_LEN, msg2); | ||
724 | |||
725 | /* Free up memory for unserialized and intermediate values */ | ||
726 | gcry_mpi_release(r); | ||
727 | gcry_mpi_release(qb1); | ||
728 | gcry_mpi_release(qb2); | ||
729 | otrl_sm_msg_free(&msg2, SM_MSG2_LEN); | ||
730 | |||
731 | return gcry_error(GPG_ERR_NO_ERROR); | ||
732 | } | ||
733 | |||
734 | /* Create third message in SMP exchange. Input is a message generated | ||
735 | * by otrl_sm_step2b. Output is a serialized mpi array whose elements | ||
736 | * correspond to the following: | ||
737 | * [0] = pa, [1] = qa, Alice's halves of the (Pa/Pb) and (Qa/Qb) values | ||
738 | * [2] = cp, [3] = d5, [4] = d6, Alice's ZK proof that pa, qa formed correctly | ||
739 | * [5] = ra, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3a | ||
740 | * [6] = cr, [7] = d7, Alice's ZK proof that ra is formed correctly */ | ||
741 | gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen) | ||
742 | { | ||
743 | /* Read from input to find the mpis */ | ||
744 | gcry_mpi_t r, qa1, qa2, inv; | ||
745 | gcry_mpi_t *msg2; | ||
746 | gcry_mpi_t *msg3; | ||
747 | gcry_error_t err; | ||
748 | |||
749 | *output = NULL; | ||
750 | *outputlen = 0; | ||
751 | astate->sm_prog_state = OTRL_SMP_PROG_CHEATED; | ||
752 | |||
753 | err = unserialize_mpi_array(&msg2, SM_MSG2_LEN, input, inputlen); | ||
754 | if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; | ||
755 | |||
756 | if (check_group_elem(msg2[0]) || check_group_elem(msg2[3]) || | ||
757 | check_group_elem(msg2[6]) || check_group_elem(msg2[7]) || | ||
758 | check_expon(msg2[2]) || check_expon(msg2[5]) || | ||
759 | check_expon(msg2[9]) || check_expon(msg2[10])) { | ||
760 | return gcry_error(GPG_ERR_INV_VALUE); | ||
761 | } | ||
762 | |||
763 | otrl_sm_msg3_init(&msg3); | ||
764 | |||
765 | /* Store Bob's g3a value for later in the protocol */ | ||
766 | gcry_mpi_set(astate->g3o, msg2[3]); | ||
767 | |||
768 | /* Verify Bob's knowledge of discreet log proofs */ | ||
769 | if (otrl_sm_check_know_log(msg2[1], msg2[2], astate->g1, msg2[0], 3) || | ||
770 | otrl_sm_check_know_log(msg2[4], msg2[5], astate->g1, msg2[3], 4)) { | ||
771 | return gcry_error(GPG_ERR_INV_VALUE); | ||
772 | } | ||
773 | |||
774 | /* Combine the two halves from Bob and Alice and determine g2 and g3 */ | ||
775 | gcry_mpi_powm(astate->g2, msg2[0], astate->x2, SM_MODULUS); | ||
776 | gcry_mpi_powm(astate->g3, msg2[3], astate->x3, SM_MODULUS); | ||
777 | |||
778 | /* Verify Bob's coordinate equality proof */ | ||
779 | if (otrl_sm_check_equal_coords(msg2[8], msg2[9], msg2[10], msg2[6], msg2[7], astate, 5)) | ||
780 | return gcry_error(GPG_ERR_INV_VALUE); | ||
781 | |||
782 | /* Calculate P and Q values for Alice */ | ||
783 | r = randomExponent(); | ||
784 | qa1 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
785 | qa2 = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
786 | gcry_mpi_powm(astate->p, astate->g3, r, SM_MODULUS); | ||
787 | gcry_mpi_set(msg3[0], astate->p); | ||
788 | gcry_mpi_powm(qa1, astate->g1, r, SM_MODULUS); | ||
789 | gcry_mpi_powm(qa2, astate->g2, astate->secret, SM_MODULUS); | ||
790 | gcry_mpi_mulm(astate->q, qa1, qa2, SM_MODULUS); | ||
791 | gcry_mpi_set(msg3[1], astate->q); | ||
792 | |||
793 | otrl_sm_proof_equal_coords(&(msg3[2]), &(msg3[3]), &(msg3[4]), astate, r, 6); | ||
794 | |||
795 | /* Calculate Ra and proof */ | ||
796 | inv = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
797 | gcry_mpi_invm(inv, msg2[6], SM_MODULUS); | ||
798 | gcry_mpi_mulm(astate->pab, astate->p, inv, SM_MODULUS); | ||
799 | gcry_mpi_invm(inv, msg2[7], SM_MODULUS); | ||
800 | gcry_mpi_mulm(astate->qab, astate->q, inv, SM_MODULUS); | ||
801 | gcry_mpi_powm(msg3[5], astate->qab, astate->x3, SM_MODULUS); | ||
802 | otrl_sm_proof_equal_logs(&(msg3[6]), &(msg3[7]), astate, 7); | ||
803 | |||
804 | serialize_mpi_array(output, outputlen, SM_MSG3_LEN, msg3); | ||
805 | otrl_sm_msg_free(&msg2, SM_MSG2_LEN); | ||
806 | otrl_sm_msg_free(&msg3, SM_MSG3_LEN); | ||
807 | |||
808 | gcry_mpi_release(r); | ||
809 | gcry_mpi_release(qa1); | ||
810 | gcry_mpi_release(qa2); | ||
811 | gcry_mpi_release(inv); | ||
812 | |||
813 | astate->sm_prog_state = OTRL_SMP_PROG_OK; | ||
814 | return gcry_error(GPG_ERR_NO_ERROR); | ||
815 | } | ||
816 | |||
817 | /* Create final message in SMP exchange. Input is a message generated | ||
818 | * by otrl_sm_step3. Output is a serialized mpi array whose elements | ||
819 | * correspond to the following: | ||
820 | * [0] = rb, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3b | ||
821 | * [1] = cr, [2] = d7, Bob's ZK proof that rb is formed correctly | ||
822 | * This method also checks if Alice and Bob's secrets were the same. If | ||
823 | * so, it returns NO_ERROR. If the secrets differ, an INV_VALUE error is | ||
824 | * returned instead. */ | ||
825 | gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen) | ||
826 | { | ||
827 | /* Read from input to find the mpis */ | ||
828 | int comp; | ||
829 | gcry_mpi_t inv, rab; | ||
830 | gcry_mpi_t *msg3; | ||
831 | gcry_mpi_t *msg4; | ||
832 | gcry_error_t err; | ||
833 | err = unserialize_mpi_array(&msg3, SM_MSG3_LEN, input, inputlen); | ||
834 | |||
835 | *output = NULL; | ||
836 | *outputlen = 0; | ||
837 | bstate->sm_prog_state = OTRL_SMP_PROG_CHEATED; | ||
838 | |||
839 | if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; | ||
840 | |||
841 | otrl_sm_msg4_init(&msg4); | ||
842 | |||
843 | if (check_group_elem(msg3[0]) || check_group_elem(msg3[1]) || | ||
844 | check_group_elem(msg3[5]) || check_expon(msg3[3]) || | ||
845 | check_expon(msg3[4]) || check_expon(msg3[7])) { | ||
846 | return gcry_error(GPG_ERR_INV_VALUE); | ||
847 | } | ||
848 | |||
849 | /* Verify Alice's coordinate equality proof */ | ||
850 | if (otrl_sm_check_equal_coords(msg3[2], msg3[3], msg3[4], msg3[0], msg3[1], bstate, 6)) | ||
851 | return gcry_error(GPG_ERR_INV_VALUE); | ||
852 | |||
853 | /* Find Pa/Pb and Qa/Qb */ | ||
854 | inv = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
855 | gcry_mpi_invm(inv, bstate->p, SM_MODULUS); | ||
856 | gcry_mpi_mulm(bstate->pab, msg3[0], inv, SM_MODULUS); | ||
857 | gcry_mpi_invm(inv, bstate->q, SM_MODULUS); | ||
858 | gcry_mpi_mulm(bstate->qab, msg3[1], inv, SM_MODULUS); | ||
859 | |||
860 | /* Verify Alice's log equality proof */ | ||
861 | if (otrl_sm_check_equal_logs(msg3[6], msg3[7], msg3[5], bstate, 7)) | ||
862 | return gcry_error(GPG_ERR_INV_VALUE); | ||
863 | |||
864 | /* Calculate Rb and proof */ | ||
865 | gcry_mpi_powm(msg4[0], bstate->qab, bstate->x3, SM_MODULUS); | ||
866 | otrl_sm_proof_equal_logs(&(msg4[1]), &(msg4[2]), bstate, 8); | ||
867 | |||
868 | serialize_mpi_array(output, outputlen, SM_MSG4_LEN, msg4); | ||
869 | |||
870 | /* Calculate Rab and verify that secrets match */ | ||
871 | rab = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
872 | gcry_mpi_powm(rab, msg3[5], bstate->x3, SM_MODULUS); | ||
873 | comp = gcry_mpi_cmp(rab, bstate->pab); | ||
874 | |||
875 | /* Clean up everything allocated in this step */ | ||
876 | otrl_sm_msg_free(&msg3, SM_MSG3_LEN); | ||
877 | otrl_sm_msg_free(&msg4, SM_MSG4_LEN); | ||
878 | gcry_mpi_release(rab); | ||
879 | gcry_mpi_release(inv); | ||
880 | |||
881 | bstate->sm_prog_state = comp ? OTRL_SMP_PROG_FAILED : | ||
882 | OTRL_SMP_PROG_SUCCEEDED; | ||
883 | |||
884 | if (comp) | ||
885 | return gcry_error(GPG_ERR_INV_VALUE); | ||
886 | else | ||
887 | return gcry_error(GPG_ERR_NO_ERROR); | ||
888 | } | ||
889 | |||
890 | /* Receives the final SMP message, which was generated in otrl_sm_step. | ||
891 | * This method checks if Alice and Bob's secrets were the same. If | ||
892 | * so, it returns NO_ERROR. If the secrets differ, an INV_VALUE error is | ||
893 | * returned instead. */ | ||
894 | gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen) | ||
895 | { | ||
896 | /* Read from input to find the mpis */ | ||
897 | int comp; | ||
898 | gcry_mpi_t rab; | ||
899 | gcry_mpi_t *msg4; | ||
900 | gcry_error_t err; | ||
901 | err = unserialize_mpi_array(&msg4, SM_MSG4_LEN, input, inputlen); | ||
902 | astate->sm_prog_state = OTRL_SMP_PROG_CHEATED; | ||
903 | |||
904 | if (err != gcry_error(GPG_ERR_NO_ERROR)) return err; | ||
905 | |||
906 | if (check_group_elem(msg4[0]) || check_expon(msg4[2])) { | ||
907 | return gcry_error(GPG_ERR_INV_VALUE); | ||
908 | } | ||
909 | |||
910 | /* Verify Bob's log equality proof */ | ||
911 | if (otrl_sm_check_equal_logs(msg4[1], msg4[2], msg4[0], astate, 8)) | ||
912 | return gcry_error(GPG_ERR_INV_VALUE); | ||
913 | |||
914 | /* Calculate Rab and verify that secrets match */ | ||
915 | rab = gcry_mpi_new(SM_MOD_LEN_BITS); | ||
916 | gcry_mpi_powm(rab, msg4[0], astate->x3, SM_MODULUS); | ||
917 | |||
918 | comp = gcry_mpi_cmp(rab, astate->pab); | ||
919 | gcry_mpi_release(rab); | ||
920 | otrl_sm_msg_free(&msg4, SM_MSG4_LEN); | ||
921 | |||
922 | astate->sm_prog_state = comp ? OTRL_SMP_PROG_FAILED : | ||
923 | OTRL_SMP_PROG_SUCCEEDED; | ||
924 | |||
925 | if (comp) | ||
926 | return gcry_error(GPG_ERR_INV_VALUE); | ||
927 | else | ||
928 | return gcry_error(GPG_ERR_NO_ERROR); | ||
929 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/sm.h b/linden/indra/libotr/libotr-3.2.0/src/sm.h new file mode 100755 index 0000000..2e94f07 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/sm.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __SM_H__ | ||
21 | #define __SM_H__ | ||
22 | |||
23 | #include <gcrypt.h> | ||
24 | |||
25 | #define SM_HASH_ALGORITHM GCRY_MD_SHA256 | ||
26 | #define SM_DIGEST_SIZE 32 | ||
27 | |||
28 | typedef enum { | ||
29 | OTRL_SMP_EXPECT1, | ||
30 | OTRL_SMP_EXPECT2, | ||
31 | OTRL_SMP_EXPECT3, | ||
32 | OTRL_SMP_EXPECT4, | ||
33 | OTRL_SMP_EXPECT5 | ||
34 | } NextExpectedSMP; | ||
35 | |||
36 | typedef enum { | ||
37 | OTRL_SMP_PROG_OK = 0, /* All is going fine so far */ | ||
38 | OTRL_SMP_PROG_CHEATED = -2, /* Some verification failed */ | ||
39 | OTRL_SMP_PROG_FAILED = -1, /* The secrets didn't match */ | ||
40 | OTRL_SMP_PROG_SUCCEEDED = 1 /* The SMP completed successfully */ | ||
41 | } OtrlSMProgState; | ||
42 | |||
43 | typedef struct { | ||
44 | gcry_mpi_t secret, x2, x3, g1, g2, g3, g3o, p, q, pab, qab; | ||
45 | NextExpectedSMP nextExpected; | ||
46 | int received_question; /* 1 if we received a question in an SMP1Q TLV */ | ||
47 | OtrlSMProgState sm_prog_state; | ||
48 | } OtrlSMState; | ||
49 | |||
50 | typedef OtrlSMState OtrlSMAliceState; | ||
51 | typedef OtrlSMState OtrlSMBobState; | ||
52 | |||
53 | /* | ||
54 | * Call this once, at plugin load time. It sets up the modulus and | ||
55 | * generator MPIs. | ||
56 | */ | ||
57 | void otrl_sm_init(void); | ||
58 | |||
59 | /* | ||
60 | * Initialize the fields of a SM state. | ||
61 | */ | ||
62 | void otrl_sm_state_new(OtrlSMState *smst); | ||
63 | |||
64 | /* | ||
65 | * Initialize the fields of a SM state. Called the first time that | ||
66 | * a user begins an SMP session. | ||
67 | */ | ||
68 | void otrl_sm_state_init(OtrlSMState *smst); | ||
69 | |||
70 | /* | ||
71 | * Deallocate the contents of a OtrlSMState (but not the OtrlSMState | ||
72 | * itself) | ||
73 | */ | ||
74 | void otrl_sm_state_free(OtrlSMState *smst); | ||
75 | |||
76 | gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate, const unsigned char* secret, int secretlen, unsigned char** output, int* outputlen); | ||
77 | gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, int received_question); | ||
78 | gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret, int secretlen, unsigned char **output, int* outputlen); | ||
79 | gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen); | ||
80 | gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen); | ||
81 | gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen); | ||
82 | |||
83 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/tlv.c b/linden/indra/libotr/libotr-3.2.0/src/tlv.c new file mode 100755 index 0000000..0cea7b5 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/tlv.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <assert.h> | ||
23 | |||
24 | #include "tlv.h" | ||
25 | |||
26 | /* Make a single TLV, copying the supplied data */ | ||
27 | OtrlTLV *otrl_tlv_new(unsigned short type, unsigned short len, | ||
28 | const unsigned char *data) | ||
29 | { | ||
30 | OtrlTLV *tlv = malloc(sizeof(OtrlTLV)); | ||
31 | assert(tlv != NULL); | ||
32 | tlv->type = type; | ||
33 | tlv->len = len; | ||
34 | tlv->data = malloc(len + 1); | ||
35 | assert(tlv->data != NULL); | ||
36 | memmove(tlv->data, data, len); | ||
37 | tlv->data[tlv->len] = '\0'; | ||
38 | tlv->next = NULL; | ||
39 | return tlv; | ||
40 | } | ||
41 | |||
42 | /* Construct a chain of TLVs from the given data */ | ||
43 | OtrlTLV *otrl_tlv_parse(const unsigned char *serialized, size_t seriallen) | ||
44 | { | ||
45 | OtrlTLV *tlv = NULL; | ||
46 | OtrlTLV **tlvp = &tlv; | ||
47 | while (seriallen >= 4) { | ||
48 | unsigned short type = (serialized[0] << 8) + serialized[1]; | ||
49 | unsigned short len = (serialized[2] << 8) + serialized[3]; | ||
50 | serialized += 4; seriallen -=4; | ||
51 | if (seriallen < len) break; | ||
52 | *tlvp = otrl_tlv_new(type, len, serialized); | ||
53 | serialized += len; | ||
54 | seriallen -= len; | ||
55 | tlvp = &((*tlvp)->next); | ||
56 | } | ||
57 | return tlv; | ||
58 | } | ||
59 | |||
60 | /* Deallocate a chain of TLVs */ | ||
61 | void otrl_tlv_free(OtrlTLV *tlv) | ||
62 | { | ||
63 | while (tlv) { | ||
64 | OtrlTLV *next = tlv->next; | ||
65 | free(tlv->data); | ||
66 | free(tlv); | ||
67 | tlv = next; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /* Find the serialized length of a chain of TLVs */ | ||
72 | size_t otrl_tlv_seriallen(const OtrlTLV *tlv) | ||
73 | { | ||
74 | size_t totlen = 0; | ||
75 | while (tlv) { | ||
76 | totlen += tlv->len + 4; | ||
77 | tlv = tlv->next; | ||
78 | } | ||
79 | return totlen; | ||
80 | } | ||
81 | |||
82 | /* Serialize a chain of TLVs. The supplied buffer must already be large | ||
83 | * enough. */ | ||
84 | void otrl_tlv_serialize(unsigned char *buf, const OtrlTLV *tlv) | ||
85 | { | ||
86 | while (tlv) { | ||
87 | buf[0] = (tlv->type >> 8) & 0xff; | ||
88 | buf[1] = tlv->type & 0xff; | ||
89 | buf[2] = (tlv->len >> 8) & 0xff; | ||
90 | buf[3] = tlv->len & 0xff; | ||
91 | buf += 4; | ||
92 | memmove(buf, tlv->data, tlv->len); | ||
93 | buf += tlv->len; | ||
94 | tlv = tlv->next; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /* Return the first TLV with the given type in the chain, or NULL if one | ||
99 | * isn't found. (The tlvs argument isn't const because the return type | ||
100 | * needs to be non-const.) */ | ||
101 | OtrlTLV *otrl_tlv_find(OtrlTLV *tlvs, unsigned short type) | ||
102 | { | ||
103 | while (tlvs) { | ||
104 | if (tlvs->type == type) return tlvs; | ||
105 | tlvs = tlvs->next; | ||
106 | } | ||
107 | return NULL; | ||
108 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/tlv.h b/linden/indra/libotr/libotr-3.2.0/src/tlv.h new file mode 100755 index 0000000..affe0d5 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/tlv.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __TLV_H__ | ||
21 | #define __TLV_H__ | ||
22 | |||
23 | typedef struct s_OtrlTLV { | ||
24 | unsigned short type; | ||
25 | unsigned short len; | ||
26 | unsigned char *data; | ||
27 | struct s_OtrlTLV *next; | ||
28 | } OtrlTLV; | ||
29 | |||
30 | /* TLV types */ | ||
31 | |||
32 | /* This is just padding for the encrypted message, and should be ignored. */ | ||
33 | #define OTRL_TLV_PADDING 0x0000 | ||
34 | |||
35 | /* The sender has thrown away his OTR session keys with you */ | ||
36 | #define OTRL_TLV_DISCONNECTED 0x0001 | ||
37 | |||
38 | /* The message contains a step in the Socialist Millionaires' Protocol. */ | ||
39 | #define OTRL_TLV_SMP1 0x0002 | ||
40 | #define OTRL_TLV_SMP2 0x0003 | ||
41 | #define OTRL_TLV_SMP3 0x0004 | ||
42 | #define OTRL_TLV_SMP4 0x0005 | ||
43 | #define OTRL_TLV_SMP_ABORT 0x0006 | ||
44 | /* Like OTRL_TLV_SMP1, but there's a question for the buddy at the | ||
45 | * beginning */ | ||
46 | #define OTRL_TLV_SMP1Q 0x0007 | ||
47 | |||
48 | /* Make a single TLV, copying the supplied data */ | ||
49 | OtrlTLV *otrl_tlv_new(unsigned short type, unsigned short len, | ||
50 | const unsigned char *data); | ||
51 | |||
52 | /* Construct a chain of TLVs from the given data */ | ||
53 | OtrlTLV *otrl_tlv_parse(const unsigned char *serialized, size_t seriallen); | ||
54 | |||
55 | /* Deallocate a chain of TLVs */ | ||
56 | void otrl_tlv_free(OtrlTLV *tlv); | ||
57 | |||
58 | /* Find the serialized length of a chain of TLVs */ | ||
59 | size_t otrl_tlv_seriallen(const OtrlTLV *tlv); | ||
60 | |||
61 | /* Serialize a chain of TLVs. The supplied buffer must already be large | ||
62 | * enough. */ | ||
63 | void otrl_tlv_serialize(unsigned char *buf, const OtrlTLV *tlv); | ||
64 | |||
65 | /* Return the first TLV with the given type in the chain, or NULL if one | ||
66 | * isn't found. (The tlvs argument isn't const because the return type | ||
67 | * needs to be non-const.) */ | ||
68 | OtrlTLV *otrl_tlv_find(OtrlTLV *tlvs, unsigned short type); | ||
69 | |||
70 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/userstate.c b/linden/indra/libotr/libotr-3.2.0/src/userstate.c new file mode 100755 index 0000000..6de95b8 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/userstate.c | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* system headers */ | ||
21 | #include <stdlib.h> | ||
22 | |||
23 | /* libotr headers */ | ||
24 | #include "context.h" | ||
25 | #include "privkey.h" | ||
26 | #include "userstate.h" | ||
27 | |||
28 | /* Create a new OtrlUserState. Most clients will only need one of | ||
29 | * these. A OtrlUserState encapsulates the list of known fingerprints | ||
30 | * and the list of private keys; if you have separate files for these | ||
31 | * things for (say) different users, use different OtrlUserStates. If | ||
32 | * you've got only one user, with multiple accounts all stored together | ||
33 | * in the same fingerprint store and privkey store files, use just one | ||
34 | * OtrlUserState. */ | ||
35 | OtrlUserState otrl_userstate_create(void) | ||
36 | { | ||
37 | OtrlUserState us = malloc(sizeof(struct s_OtrlUserState)); | ||
38 | if (!us) return NULL; | ||
39 | us->context_root = NULL; | ||
40 | us->privkey_root = NULL; | ||
41 | |||
42 | return us; | ||
43 | } | ||
44 | |||
45 | /* Free a OtrlUserState */ | ||
46 | void otrl_userstate_free(OtrlUserState us) | ||
47 | { | ||
48 | otrl_context_forget_all(us); | ||
49 | otrl_privkey_forget_all(us); | ||
50 | free(us); | ||
51 | } | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/userstate.h b/linden/indra/libotr/libotr-3.2.0/src/userstate.h new file mode 100755 index 0000000..8525df0 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/userstate.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __USERSTATE_H__ | ||
21 | #define __USERSTATE_H__ | ||
22 | |||
23 | typedef struct s_OtrlUserState* OtrlUserState; | ||
24 | |||
25 | #include "context.h" | ||
26 | #include "privkey-t.h" | ||
27 | |||
28 | struct s_OtrlUserState { | ||
29 | ConnContext *context_root; | ||
30 | OtrlPrivKey *privkey_root; | ||
31 | }; | ||
32 | |||
33 | /* Create a new OtrlUserState. Most clients will only need one of | ||
34 | * these. A OtrlUserState encapsulates the list of known fingerprints | ||
35 | * and the list of private keys; if you have separate files for these | ||
36 | * things for (say) different users, use different OtrlUserStates. If | ||
37 | * you've got only one user, with multiple accounts all stored together | ||
38 | * in the same fingerprint store and privkey store files, use just one | ||
39 | * OtrlUserState. */ | ||
40 | OtrlUserState otrl_userstate_create(void); | ||
41 | |||
42 | /* Free a OtrlUserState */ | ||
43 | void otrl_userstate_free(OtrlUserState us); | ||
44 | |||
45 | #endif | ||
diff --git a/linden/indra/libotr/libotr-3.2.0/src/version.h b/linden/indra/libotr/libotr-3.2.0/src/version.h new file mode 100755 index 0000000..11cb586 --- /dev/null +++ b/linden/indra/libotr/libotr-3.2.0/src/version.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Off-the-Record Messaging library | ||
3 | * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov | ||
4 | * <otr@cypherpunks.ca> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2.1 of the GNU Lesser General | ||
8 | * Public License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef __VERSION_H__ | ||
21 | #define __VERSION_H__ | ||
22 | |||
23 | #define OTRL_VERSION "3.2.0" | ||
24 | |||
25 | #define OTRL_VERSION_MAJOR 3 | ||
26 | #define OTRL_VERSION_MINOR 2 | ||
27 | #define OTRL_VERSION_SUB 0 | ||
28 | |||
29 | #endif | ||