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