xref: /petsc/src/sys/webclient/client.c (revision 0efc6a0385228cde9a68b4e67359bfe0b0532191)
1b967cddfSBarry Smith 
2*0efc6a03SBarry Smith #include <petscwebclient.h>
3b967cddfSBarry Smith 
4b967cddfSBarry Smith static BIO *bio_err = NULL;
5b967cddfSBarry Smith 
6b967cddfSBarry Smith #define PASSWORD "password"
7b967cddfSBarry Smith 
8b967cddfSBarry Smith #if defined(PETSC_USE_CERTIFICATE)
9b967cddfSBarry Smith static int password_cb(char *buf,int num, int rwflag,void *userdata)
10b967cddfSBarry Smith {
11b967cddfSBarry Smith   if (num < strlen(PASSWORD)+1) return(0);
12b967cddfSBarry Smith   strcpy(buf,PASSWORD);
13b967cddfSBarry Smith   return(strlen(PASSWORD));
14b967cddfSBarry Smith }
15b967cddfSBarry Smith #endif
16b967cddfSBarry Smith 
17b967cddfSBarry Smith static void sigpipe_handle(int x)
18b967cddfSBarry Smith {
19b967cddfSBarry Smith }
20b967cddfSBarry Smith 
21b967cddfSBarry Smith #undef __FUNCT__
22b967cddfSBarry Smith #define __FUNCT__ "PetscSSLInitializeContext"
23b967cddfSBarry Smith /*
24b967cddfSBarry Smith     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
25b967cddfSBarry Smith 
26b967cddfSBarry Smith     If built with PETSC_USE_CERTIFICATE requires the user have created a self-signed certificate with
27b967cddfSBarry Smith 
28b967cddfSBarry Smith $    ./CA.pl  -newcert  (using the passphrase of password)
29b967cddfSBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
30b967cddfSBarry Smith 
31b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
32b967cddfSBarry Smith     silly but it was all I could figure out.
33b967cddfSBarry Smith 
34b967cddfSBarry Smith */
35b967cddfSBarry Smith PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
36b967cddfSBarry Smith {
37b967cddfSBarry Smith     SSL_METHOD     *meth;
38b967cddfSBarry Smith     SSL_CTX        *ctx;
39b967cddfSBarry Smith #if defined(PETSC_USE_CERTIFICATE)
40b967cddfSBarry Smith     char           keyfile[PETSC_MAX_PATH_LEN];
41b967cddfSBarry Smith     PetscBool      exists;
42b967cddfSBarry Smith     PetscErrorCode ierr;
43b967cddfSBarry Smith #endif
44b967cddfSBarry Smith 
45b967cddfSBarry Smith     PetscFunctionBegin;
46b967cddfSBarry Smith     if (!bio_err){
47b967cddfSBarry Smith       SSL_library_init();
48b967cddfSBarry Smith       SSL_load_error_strings();
49b967cddfSBarry Smith       bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
50b967cddfSBarry Smith     }
51b967cddfSBarry Smith 
52b967cddfSBarry Smith     /* Set up a SIGPIPE handler */
53b967cddfSBarry Smith     signal(SIGPIPE,sigpipe_handle);
54b967cddfSBarry Smith 
55b967cddfSBarry Smith     meth = SSLv23_method();
56b967cddfSBarry Smith     ctx  = SSL_CTX_new(meth);
57b967cddfSBarry Smith 
58b967cddfSBarry Smith #if defined(PETSC_USE_CERTIFICATE)
59b967cddfSBarry Smith     /* Locate keyfile */
60b967cddfSBarry Smith     ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr);
61b967cddfSBarry Smith     ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
62b967cddfSBarry Smith     if (!exists) {
63b967cddfSBarry Smith       ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
64b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr);
65b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr);
66b967cddfSBarry Smith       ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
67b967cddfSBarry Smith       if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
68b967cddfSBarry Smith     }
69b967cddfSBarry Smith 
70b967cddfSBarry Smith     /* Load our keys and certificates*/
71b967cddfSBarry Smith     if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file");
72b967cddfSBarry Smith 
73b967cddfSBarry Smith     SSL_CTX_set_default_passwd_cb(ctx,password_cb);
74b967cddfSBarry Smith     if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file");
75b967cddfSBarry Smith #endif
76b967cddfSBarry Smith 
77b967cddfSBarry Smith     *octx = ctx;
78b967cddfSBarry Smith     PetscFunctionReturn(0);
79b967cddfSBarry Smith }
80b967cddfSBarry Smith 
81b967cddfSBarry Smith #undef __FUNCT__
82b967cddfSBarry Smith #define __FUNCT__ "PetscSSLDestroyContext"
83b967cddfSBarry Smith PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
84b967cddfSBarry Smith {
85b967cddfSBarry Smith   PetscFunctionBegin;
86b967cddfSBarry Smith   SSL_CTX_free(ctx);
87b967cddfSBarry Smith   PetscFunctionReturn(0);
88b967cddfSBarry Smith }
89b967cddfSBarry Smith 
90b967cddfSBarry Smith #undef __FUNCT__
91b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSRequest"
92b967cddfSBarry Smith /*
93b967cddfSBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
94b967cddfSBarry Smith 
95b967cddfSBarry Smith    Input Parameters:
96b967cddfSBarry Smith +   type - either "POST" or "GET"
97b967cddfSBarry Smith .   url - complete URL of request including https://
98b967cddfSBarry Smith .   header - additional header information, may be NULL
99b967cddfSBarry Smith .   ctype - data type of body, for example application/json
100b967cddfSBarry Smith .   body - data to send to server
101b967cddfSBarry Smith .   ssl - obtained with PetscHTTPSConnect()
102b967cddfSBarry Smith -   buffsize - size of buffer
103b967cddfSBarry Smith 
104b967cddfSBarry Smith    Output Parameter:
105b967cddfSBarry Smith .   buff - everything returned from server
106b967cddfSBarry Smith  */
107*0efc6a03SBarry Smith PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize)
108b967cddfSBarry Smith {
109b967cddfSBarry Smith   char           *request=0;
110b967cddfSBarry Smith   char           contentlength[40],contenttype[80];
111b967cddfSBarry Smith   int            r;
112b967cddfSBarry Smith   size_t         request_len,len,headlen,bodylen,contentlen,urllen,typelen,contenttypelen = 0;
113b967cddfSBarry Smith   PetscErrorCode ierr;
114b967cddfSBarry Smith   PetscBool      flg;
115b967cddfSBarry Smith 
116b967cddfSBarry Smith   PetscFunctionBegin;
117b967cddfSBarry Smith   ierr = PetscStrbeginswith(url,"https://",&flg);CHKERRQ(ierr);
118b967cddfSBarry Smith   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"URL must begin with https://");
119b967cddfSBarry Smith   if (header) {
120b967cddfSBarry Smith     ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr);
121b967cddfSBarry Smith     if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n");
122b967cddfSBarry Smith   }
123b967cddfSBarry Smith 
124b967cddfSBarry Smith   ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr);
125b967cddfSBarry Smith   ierr = PetscStrlen(url,&urllen);CHKERRQ(ierr);
126b967cddfSBarry Smith   if (ctype) {
127b967cddfSBarry Smith     ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr);
128b967cddfSBarry Smith     ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr);
129b967cddfSBarry Smith   }
130b967cddfSBarry Smith   ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr);
131b967cddfSBarry Smith   ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr);
132b967cddfSBarry Smith   ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr);
133b967cddfSBarry Smith   ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr);
134b967cddfSBarry Smith 
135b967cddfSBarry Smith   /* Now construct our HTTP request */
136b967cddfSBarry Smith   request_len = typelen + 1 + urllen + 35 + headlen + contenttypelen + contentlen + bodylen + 1;
137fe278a28SBarry Smith   ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr);
138b967cddfSBarry Smith   ierr = PetscStrcpy(request,type);CHKERRQ(ierr);
139b967cddfSBarry Smith   ierr = PetscStrcat(request," ");CHKERRQ(ierr);
140b967cddfSBarry Smith   ierr = PetscStrcat(request,url);CHKERRQ(ierr);
141b967cddfSBarry Smith   ierr = PetscStrcat(request," HTTP/1.1\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr);
142b967cddfSBarry Smith   ierr = PetscStrcat(request,header);CHKERRQ(ierr);
143b967cddfSBarry Smith   if (ctype) {
144b967cddfSBarry Smith     ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr);
145b967cddfSBarry Smith   }
146b967cddfSBarry Smith   ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr);
147b967cddfSBarry Smith   ierr = PetscStrcat(request,body);CHKERRQ(ierr);
148b967cddfSBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
149b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr);
150b967cddfSBarry Smith 
151b967cddfSBarry Smith   r = SSL_write(ssl,request,request_len);
152b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)){
153b967cddfSBarry Smith     case SSL_ERROR_NONE:
154b967cddfSBarry Smith       if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket");
155b967cddfSBarry Smith       break;
156b967cddfSBarry Smith       default:
157b967cddfSBarry Smith         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
158b967cddfSBarry Smith   }
159b967cddfSBarry Smith 
160b967cddfSBarry Smith   /* Now read the server's response, assuming  that it's terminated by a close */
161b967cddfSBarry Smith   r = SSL_read(ssl,buff,(int)buffsize);
162b967cddfSBarry Smith   len = r;
163b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)){
164b967cddfSBarry Smith   case SSL_ERROR_NONE:
165b967cddfSBarry Smith     break;
166b967cddfSBarry Smith   case SSL_ERROR_ZERO_RETURN:
167b967cddfSBarry Smith     SSL_shutdown(ssl);  /* ignore shutdown error message */
168b967cddfSBarry Smith     break;
169b967cddfSBarry Smith   case SSL_ERROR_SYSCALL:
170b967cddfSBarry Smith     break;
171b967cddfSBarry Smith   default:
172b967cddfSBarry Smith     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
173b967cddfSBarry Smith   }
174b967cddfSBarry Smith   buff[len] = 0; /* null terminate string */
175b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr);
176b967cddfSBarry Smith 
177b967cddfSBarry Smith   SSL_free(ssl);
178b967cddfSBarry Smith   ierr = PetscFree(request);CHKERRQ(ierr);
179b967cddfSBarry Smith   PetscFunctionReturn(0);
180b967cddfSBarry Smith }
181b967cddfSBarry Smith 
182b967cddfSBarry Smith #undef __FUNCT__
183b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect"
184b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
185b967cddfSBarry Smith {
186b967cddfSBarry Smith   BIO            *sbio;
187b967cddfSBarry Smith   PetscErrorCode ierr;
188b967cddfSBarry Smith 
189b967cddfSBarry Smith   PetscFunctionBegin;
190b967cddfSBarry Smith   /* Connect the TCP socket*/
191b967cddfSBarry Smith   ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr);
192b967cddfSBarry Smith 
193b967cddfSBarry Smith   /* Connect the SSL socket */
194b967cddfSBarry Smith   *ssl = SSL_new(ctx);
195b967cddfSBarry Smith   sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
196b967cddfSBarry Smith   SSL_set_bio(*ssl,sbio,sbio);
197b967cddfSBarry Smith   if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error");
198b967cddfSBarry Smith   PetscFunctionReturn(0);
199b967cddfSBarry Smith }
200b967cddfSBarry Smith 
201